A Java deep clone (deep copy) example

/**
 * This method makes a "deep clone" of any Java object it is given.
 */
 public static Object deepClone(Object object) {
   try {
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(baos);
     oos.writeObject(object);
     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
     ObjectInputStream ois = new ObjectInputStream(bais);
     return ois.readObject();
   }
   catch (Exception e) {
     e.printStackTrace();
     return null;
   }
 }

Java Exception Handling Tutorial

Exception handling is a very important yet often neglected aspect of writing robust software.
When an error occurs in a Java program it usually results in an exception being thrown. How you throw,
catch and handle these exception matters. There are several different ways to do so. Not all are equally
efficient and fail safe.

This trail digs deeper into exception handling in Java. The trail covers various do’s and dont’s
of Java exception handling. It also covers a few techniques for efficient and less error prone
exception handling. Hopefully you can benefit from some of these texts.

Use ANT to Build a JAR with version/build number

<target name="jar">
   <delete file="hello.jar"/>
   <property name="version.num" value="1.00"/>
   <buildnumber file="build.num"/>
   <tstamp>
     <format property="TODAY" pattern="yyyy-MM-dd HH:mm:ss" />
   </tstamp>

   <manifest file="MANIFEST.MF">
      <attribute name="Built-By" value="${user.name}"/>
      <attribute name="Main-Class" value="howto.Hello"/>
      <attribute name="Implementation-Version" 
             value="${version.num}-b${build.number}"/>   
      <attribute name="Built-Date" value="${TODAY}"/>                 
  </manifest>

  <jar destfile="hello.jar"
       basedir="."
       includes="**/*.class"
       manifest="MANIFEST.MF"
       />
</target>

Java 6 has a web server inside

import com.sun.net.httpserver.*

class ExampleHandler implements HttpHandler {
        void handle(HttpExchange exchange) throws IOException {
                def response = "Hello, world!"

                exchange.sendResponseHeaders(200, response.length());
                def outout = exchange.responseBody
                outout.write(response.bytes);
                outout.close();
        }
}

public class ExampleAuthenticator extends BasicAuthenticator {
        static users = [ "john": "john123" ]
 
        public ExampleAuthenticator(String realm) {
                super(realm);
        }

        @Override
        public boolean checkCredentials(String username, String password) {
                return users[username] == password;
        }
}

def server = HttpServer.create(new InetSocketAddress(8000), 0);
def context = server.createContext("/example", new ExampleHandler());
context.authenticator = new ExampleAuthenticator("Example application")
server.executor = null
server.start();

 

Java 7 w jednej krótkiej lekcji

Program w Java 6 (przed zmianami)

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

public class Test1 {

        static void usage() {
                System.out.println("Usage: <input file>");
        }

        public static void main(String[] args) {
                if (args.length == 0) {
                        usage();
                        return;
                }
        
                for (String i : args) {
                        if (i.equals("-help") || i.equals("--help") || i.equals("-h")) {
                                usage();
                                return;
                        }
                        else if (i.equals("-version") || i.equals("--version") || i.equals("-v")) {
                                System.out.println("Version 1.0  Public Domain");
                                return;
                        }
                        else {
                                if (i.startsWith("-")) {
                                        System.out.println("Unknown argument: " + i);
                                        System.exit(1);
                                }
                        }
                }
                
                BufferedReader reader = null;
                File file = new File(args[0]);
                try {
                        reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8"));
                        String line;
                        while ((line = reader.readLine()) != null) {
                                URI uri = new URI(line);
                                System.out.println(uri.getHost());
                        }
                }
                catch (IOException exception) {
                        exception.printStackTrace();
                }
                catch (URISyntaxException exception) {
                        exception.printStackTrace();
                }
                finally {
                        if (reader != null) {
                                try {
                                        reader.close();
                                }
                                catch (IOException exception) {
                                        exception.printStackTrace();
                                }
                        }
                }
        }

}

String-in-switch

Na rozgrzewkę można zastąpić wszystkie if/else pojedynczym switch/case (dobre IDE zrobi to za Ciebie). Switch dla Stringów działa dokładnie tak jak się tego spodziewamy. Jedyne na co trzeba uważać, to “i” z wartością null, które spowoduje (uwaga: niespodzianka) NullPointerException 🙂

for (String i : args) {
                        switch (i) {
                                case "-help":
                                case "--help":
                                case "-h":
                                        usage();
                                        return;
                                case "-version":
                                case "--version":
                                case "-v":
                                        System.out.println("Version 1.0  Public Domain");
                                        return;
                                default:
                                        if (i.startsWith("-")) {
                                                System.out.println("Unknown argument: " + i);
                                                System.exit(1);
                                        }
                        }
                }

AutoCloseable

Zawsze warto pamiętać o zamykaniu wszystkich nieużywanych “streamów” i innych zasobów systemowych. Od wersji 7 wszystkie autozamykalne obiekty można umieścić w jednej składni try (). Kompilator sam doda niewidzialny blok “finally”, który wywoła odpowiednią metodę “close”.

- BufferedReader reader = null;
                File file = new File(args[0]);
                + try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8"))) {
                        - reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8"));
                        String line;
                        while ((line = reader.readLine()) != null) {
                                URI uri = new URI(line);
                                System.out.println(uri.getHost());
                        }
                }
                catch (IOException exception) {
                        exception.printStackTrace();
                }
                catch (URISyntaxException exception) {
                        exception.printStackTrace();
                }
                - Sio! finally {
                        if (reader != null) {
                                try {
                                        reader.close();
                                }
                                catch (IOException exception) {
                                        exception.printStackTrace();
                                }
                        }
                }
        }

}

Multi-catch

Kolejną małą nowością jest możliwość łapania paru różnych wyjątków w jednym bloku. Typy wyjątków rozdziela się “|”. Zawsze to trochę mniej klepania i unikniemy pokusie łapania wszystkich pokemonów 😉

File file = new File(args[0]);
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8"))) {
                        String line;
                        while ((line = reader.readLine()) != null) {
                                URI uri = new URI(line);
                                System.out.println(uri.getHost());
                        }
                }
                catch (IOException | URISyntaxException exception) {
                        exception.printStackTrace();
                }
                - catch (URISyntaxException exception) {
                        exception.printStackTrace();
                }
        }

}

Nowe New IO

Po zmianach powyższy kod wygląda trochę lepiej, ale obsługa IO nadal ssie… new BufferedReader(new InputStreamReader wygląda strasznie paskudnie. Na szczęście z pomocą przychodzi java.nio.file z licznymi udogodnieniami.

+ import java.nio.charset.StandardCharsets;
+ import java.nio.file.Files;
+ import java.nio.file.Path;
+ import java.nio.file.Paths;


                - File file = new File(args[0]);
                + Path file = Paths.get(args[0]);
                // Path file = new File(args[0]).toPath(); // wersja dla leniwców
                try (BufferedReader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8)) {
                        String line;
                        while ((line = reader.readLine()) != null) {
                                URI uri = new URI(line);
                                System.out.println(uri.getHost());
                        }
                }
                catch (IOException | URISyntaxException exception) {
                        exception.printStackTrace();
                }
        }

}

Files.readAllLines

W ramach bonusu, dużo krótsza (i pewnie mniej optymalna przy dużych plikach) metoda wczytywania tekstu:

Path file = Paths.get(args[0]);
                - try (BufferedReader reader = Files.newBufferedReader(file, StandardCharsets.UTF_8)) {
                        String line;
                        while ((line = reader.readLine()) != null) {
                + try {
                        for (String line : Files.readAllLines(file, StandardCharsets.UTF_8)) {
                                URI uri = new URI(line);
                                System.out.println(uri.getHost());
                        }
                }
                catch (IOException | URISyntaxException exception) {
                        exception.printStackTrace();
                }
        }

}

Program w Java 7

Teraz nasz program wygląda pięknie… I na koniec współczujemy wszystkim użytkownikom JDK 1.4, 1.5 i 1.6 😛

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.net.URI;
import java.net.URISyntaxException;

public class Test6 {

        static void usage() {
                System.out.println("Usage: <input file>");
        }

        public static void main(String[] args) {
                if (args.length == 0) {
                        usage();
                        return;
                }
        
                for (String i : args) {
                        switch (i) {
                                case "-help":
                                case "--help":
                                case "-h":
                                        usage();
                                        return;
                                case "-version":
                                case "--version":
                                case "-v":
                                        System.out.println("Version 1.0  Public Domain");
                                        return;
                                default:
                                        if (i.startsWith("-")) {
                                                System.out.println("Unknown argument: " + i);
                                                System.exit(1);
                                        }
                        }
                }
                
                Path file = Paths.get(args[0]);
                try {
                        for (String line : Files.readAllLines(file, StandardCharsets.UTF_8)) {
                                URI uri = new URI(line);
                                System.out.println(uri.getHost());
                        }
                }
                catch (IOException | URISyntaxException exception) {
                        exception.printStackTrace();
                }
        }

}

*) Nie interesuje nas Scala.