Java 1.6/6 New Features

Content:

  1. Version numbers
  2. Release
  3. Console class
  4. Disk info
  5. Network info
  6. Callable compiler
  7. Script execution
  8. Other JDBC 4.0
  9. Array resize
  10. IDN support
  11. Wildcard in classpath
  12. Desktop class

Version numbers:

This version is officially known as Java SE 6, but often called Java 1.6. It has codename Mustang.

Java version Official name Code name Release date
1.0 JDK 1.0 January 23rd 1996
1.1 JDK 1.1 February 19th 1997
1.2 J2SE 1.2 Playground December 8th 1998
1.3 J2SE 1.3 Kestrel May 8th 2000
1.4 J2SE 1.4 Merlin February 6th 2002
1.5/5 Java SE 5 Tiger September 30th 2004
1.6/6 Java SE 6 Mustang December 11th 2006

Release:

Java 1.6 was released December 11th 2006.

In my opinion the changes in Java 1.6 are relative small - especially compared to the major changes in Java 1.5.

Console class:

Java 1.6 got a new Cosnole class that provides certain new capabilities for console IO.

Most relevant is probably the ability to read passwords without echo.

Example:

import java.io.Console;

public class C16 {
    public static void main(String[] args) {
        Console c = System.console();
        String un = c.readLine("Enter username: ");
        String pw = new String(c.readPassword("Enter password: "));
        System.out.println(un + " " + pw);
    }
}

I think it is useful but hardly revolutionary.

And I don't expect it to be used much - console applications reeadinh passwords are very rare.

Disk info:

The File class got some new capabilities to retrieve information about disk space.

Example:

import java.io.File;

public class DI16 {
    public static void main(String[] args) {
        File f = new File("C:\\");
        long free = f.getFreeSpace();
        long tot = f.getTotalSpace();
        System.out.println(free + " " + tot);
    }
}

I think it is useful.

Even though the capability has been requested several times, then I still don't think it will be used much - to rare a need.

Network info:

It has been posisble since Java 1.4 to get all IP addresses of system, but in Java 1.6 it is also possible to get all ethernet addresses.

Previous:

import java.net.NetworkInterface;
import java.net.InetAddress;
import java.util.Enumeration;

public class NI15 {
    public static void main(String[] args) throws Exception {
        Enumeration e = NetworkInterface.getNetworkInterfaces();
        while(e.hasMoreElements()) {
            NetworkInterface ni = (NetworkInterface)e.nextElement();
            System.out.println("Net interface: " + ni.getName());
            Enumeration e2 = ni.getInetAddresses();
            while (e2.hasMoreElements()){
                InetAddress ip = (InetAddress)e2.nextElement();
                System.out.println("IP address: " + ip.getHostAddress());
            }
        }
    }
}

Now:

import java.net.NetworkInterface;
import java.net.InetAddress;
import java.util.Enumeration;

public class NI16 {
    public static void main(String[] args) throws Exception {
        Enumeration e = NetworkInterface.getNetworkInterfaces();
        while(e.hasMoreElements()) {
            NetworkInterface ni = (NetworkInterface)e.nextElement();
            System.out.println("Net interface: " + ni.getName());
            Enumeration e2 = ni.getInetAddresses();
            while (e2.hasMoreElements()){
                InetAddress ip = (InetAddress)e2.nextElement();
                System.out.println("IP address: " + ip.getHostAddress());
            }
            byte[] mac = ni.getHardwareAddress();
            if(mac != null) {
                System.out.printf("%02X:%02X:%02X:%02X:%02X:%02X\n",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
            }
        }
    }
}

I think it is useful in some cases.

But I don't expect it to be used much - the need must be very rare.

Callable compiler:

It has been requested for a long time to be able to call the Java compiler directly from code instead of having to start a process with the external Java compiler.

Previous starting javac:

import java.io.PrintWriter;
import java.io.FileWriter;

public class JC15 {
    public static void main(String[] args) throws Exception {
        PrintWriter pw = new PrintWriter(new FileWriter("Temp1.java"));
        pw.println("public class Temp1 {");
        pw.println("    public void test() {");
        pw.println("        System.out.println(\"Temp1 OK\");");
        pw.println("    }");
        pw.println("}");
        pw.close();
        Runtime.getRuntime().exec(new String[] { "javac", "Temp1.java" });
        Class c = Class.forName("Temp1");
        Object o = c.newInstance();
        c.getMethod("test", new Class[] { }).invoke(o, new Object[] { });
    }
}

Now using callable compiler:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;

public class JC16 {
    public static void main(String[] args) throws Exception {
        testFileFile();
        testMemoryFile();
        testFileMemory();
        testMemoryMemory();
    }
    public static void testFileFile() throws Exception {
        PrintWriter pw = new PrintWriter(new FileWriter("Temp2.java"));
        pw.println("public class Temp2 {");
        pw.println("    public void test() {");
        pw.println("        System.out.println(\"Temp2 OK\");");
        pw.println("    }");
        pw.println("}");
        pw.close();
        compileFileFile("Temp2.java", System.err);
        Class<?> c = Class.forName("Temp2");
        Object o = c.newInstance();
        c.getMethod("test", new Class[] { }).invoke(o, new Object[] { });
    }
    public static void compileFileFile(String fnm, PrintStream err) {
        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diacol = new DiagnosticCollector<JavaFileObject>();
        StandardJavaFileManager sjfm = javac.getStandardFileManager(diacol, null, null);
        CompilationTask compile = javac.getTask(null, sjfm, diacol, Arrays.asList(new String[] { }), null,
                                                sjfm.getJavaFileObjects(new String[] { fnm }));
        boolean status = compile.call();
        if(err != null) {
            err.println("Compile status: " + status);
            for(Diagnostic<? extends JavaFileObject> dia : diacol.getDiagnostics()) {
                err.println(dia);
            }
        }
    }
    public static void testMemoryFile() throws Exception {
        String src = "public class Temp3 { public void test() { System.out.println(\"Temp3 OK\"); } }";
        compileMemoryFile(src, "Temp3", System.err);
        Class<?> c = Class.forName("Temp3");
        Object o = c.newInstance();
        c.getMethod("test", new Class[] { }).invoke(o, new Object[] { });
    }
    public static void compileMemoryFile(String src, String name, PrintStream err) {
        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diacol = new DiagnosticCollector<JavaFileObject>();
        StandardJavaFileManager sjfm = javac.getStandardFileManager(diacol, null, null);
        CompilationTask compile = javac.getTask(null, sjfm, diacol, Arrays.asList(new String[] { }), null,
                                                Arrays.asList(new JavaFileObject[] { new MemorySource(name, src) }));
        boolean status = compile.call();
        if(err != null) {
            err.println("Compile status: " + status);
            for(Diagnostic<? extends JavaFileObject> dia : diacol.getDiagnostics()) {
                err.println(dia);
            }
        }
    }
    public static void testFileMemory() throws Exception {
        PrintWriter pw = new PrintWriter(new FileWriter("Temp4.java"));
        pw.println("public class Temp4 {");
        pw.println("    public void test() {");
        pw.println("        System.out.println(\"Temp4 OK\");");
        pw.println("    }");
        pw.println("}");
        pw.close();
        SpecialClassLoader xcl = new SpecialClassLoader();
        compileFileMemory("Temp4.java", xcl, System.err);
        Class<?> c = Class.forName("Temp4", true, xcl);
        Object o = c.newInstance();
        c.getMethod("test", new Class[] { }).invoke(o, new Object[] { });
    }
    public static void compileFileMemory(String fnm, SpecialClassLoader xcl, PrintStream err) {
        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diacol = new DiagnosticCollector<JavaFileObject>();
        StandardJavaFileManager sjfm = javac.getStandardFileManager(diacol, null, null);
        SpecialJavaFileManager xfm = new SpecialJavaFileManager(sjfm, xcl);
        CompilationTask compile = javac.getTask(null, xfm, diacol, Arrays.asList(new String[] { }), null,
                                                sjfm.getJavaFileObjects(new String[] { fnm }));
        boolean status = compile.call();
        if(err != null) {
            err.println("Compile status: " + status);
            for(Diagnostic<? extends JavaFileObject> dia : diacol.getDiagnostics()) {
                err.println(dia);
            }
        }
    }
    public static void testMemoryMemory() throws Exception {
        String src = "public class Temp5 { public void test() { System.out.println(\"Temp5 OK\"); } }";
        SpecialClassLoader xcl = new SpecialClassLoader();
        compileMemoryMemory(src, "Temp5", xcl, System.err);
        Class<?> c = Class.forName("Temp5", true, xcl);
        Object o = c.newInstance();
        c.getMethod("test", new Class[] { }).invoke(o, new Object[] { });
    }
    public static void compileMemoryMemory(String src, String name, SpecialClassLoader xcl, PrintStream err) {
        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diacol = new DiagnosticCollector<JavaFileObject>();
        StandardJavaFileManager sjfm = javac.getStandardFileManager(diacol, null, null);
        SpecialJavaFileManager xfm = new SpecialJavaFileManager(sjfm, xcl);
        CompilationTask compile = javac.getTask(null, xfm, diacol, Arrays.asList(new String[] { }), null,
                                                Arrays.asList(new JavaFileObject[] { new MemorySource(name, src) }));
        boolean status = compile.call();
        if(err != null) {
            err.println("Compile status: " + status);
            for(Diagnostic<? extends JavaFileObject> dia : diacol.getDiagnostics()) {
                err.println(dia);
            }
        }
    }
}

class MemorySource extends SimpleJavaFileObject {
    private String src;
    public MemorySource(String name, String src) {
        super(URI.create("string:///" + name + ".java"), Kind.SOURCE);
        this.src = src;
    }
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return src;
    }
    public OutputStream openOutputStream() {
        throw new IllegalStateException();
    }
    public InputStream openInputStream() {
        return new ByteArrayInputStream(src.getBytes());
    }
}

class MemoryByteCode extends SimpleJavaFileObject {
    private ByteArrayOutputStream baos;
    public MemoryByteCode(String name) {
        super(URI.create("byte:///" + name + ".class"), Kind.CLASS);
    }
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        throw new IllegalStateException();
    }
    public OutputStream openOutputStream() {
        baos = new ByteArrayOutputStream();
        return baos;
    }
    public InputStream openInputStream() {
        throw new IllegalStateException();
    }
    public byte[] getBytes() {
        return baos.toByteArray();
    }
}

class SpecialJavaFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
    private SpecialClassLoader xcl;
    public SpecialJavaFileManager(StandardJavaFileManager sjfm, SpecialClassLoader xcl) {
        super(sjfm);
        this.xcl = xcl;
    }
    public JavaFileObject getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
        MemoryByteCode mbc = new MemoryByteCode(name);
        xcl.addClass(name, mbc);
        return mbc;
    }
}

class SpecialClassLoader extends ClassLoader {
    private Map<String,MemoryByteCode> m;
    public SpecialClassLoader() {
        m = new HashMap<String, MemoryByteCode>();
    }
    protected Class<?> findClass(String name) {
        MemoryByteCode mbc = m.get(name);
        return defineClass(name, mbc.getBytes(), 0, mbc.getBytes().length);
    }
    public void addClass(String name, MemoryByteCode mbc) {
        m.put(name, mbc);
    }
}

Very useful. But I don't understand why they made the API so complex. The .NET callable compiler API is 100 times simpler and works fine.

I think it will over time replace some of the byte code generators out there.

UPDATE: I was wrong - it did not.

Script execution:

Java 1.6 got support for embedded script engines in Java applications, so it is possible to get executed a script snippet (like JavaScript) from within ones Java application.

Example:

import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;

public class S16 {
    public static void main(String[] args) throws Exception {
        ScriptEngineManager mgr = new ScriptEngineManager();
        ScriptEngine js = mgr.getEngineByName("js");
        System.out.println(js.eval("(1+2)*(3+4)"));
        js.put("a", 1);
        js.put("b", 2);
        js.put("c", 3);
        System.out.println(js.eval("a+b+c"));
        System.out.println(js.eval("var x = 1; var y = 4; var z = 9; x+y+z"));
    }
}

Java ships with JavaScript engine, but other engines can be added.

Very cute, but I don't know how useful it really is.

I don't expect it to see much use.

Other JDBC 4.0:

Java 1.6 comes with JDBC 4.0 and it has several improvements over previous versions.

Including:

I think this is very interesting changes.

And I expect them to be used when JDBC 4.0 compliant drivers start being rolled out at some point in time.

Array resize:

Java 1.6 had made it easier to resize an array.

Previous:

public class AR15 {
    public static void main(String[] args) {
        int[] ia = new int[2];
        ia[0] = 1;
        ia[1] = 2;
        int[] ia2 = new int[4];
        System.arraycopy(ia, 0, ia2, 0, 2);
        ia2[2] = 3;
        ia2[3] = 4;
        for(int i = 0; i < ia2.length; i++) {
            System.out.println(ia2[i]);
        }
    }
}

Now:

import java.util.*;

public class AR16 {
    public static void main(String[] args) {
        int[] ia = new int[2];
        ia[0] = 1;
        ia[1] = 2;
        int[] ia2 = Arrays.copyOf(ia, 4);
        ia2[2] = 3;
        ia2[3] = 4;
        for(int i = 0; i < ia2.length; i++) {
            System.out.println(ia2[i]);
        }
    }
}

I think this is very practical but not very important.

I think it will be used.

IDN support:

Java 1,6 got support fr IDN.

The java.util.IDN class has a toASCII and a toUnicode method to convert domain names with non-ASCII characters.

Example:

import java.net.*;

public class IDN16 {
    public static void main(String[] args) {
        System.out.println(IDN.toASCII("www.rød-grød-med-fløde.dk"));
    }
}

I think this is useful but not important.

And I don't think it will be used much - too rare a need.

Wildcard in classpath:

An * in classpath means that all jar files in the directory get added to the classpath.

Windows example:

java -classpath .;C:\foobar\lib\* MainClass

will add all jar files in C:\foobar\lib to classpath.

I think this is very useful.

And I think it will be used.

Desktop class:

Java 1.6 got a Desktop class for various operating system specific stuff.

Including the ability to start a wen browser with a specific URL.

Before Java 1.6 is was necessary to write some operating system and web browser specific code:

public class B15 {
    public static void main(String[] args) throws Exception {
        Runtime.getRuntime().exec(new String[] { "C:\\Program Files\\Mozilla Firefox\\firefox.exe", "http://www.eksperten.dk/" });
    }
}

In Java 1.6 one can write a general solution:

import java.net.URI;
import java.awt.Desktop;

public class B16 {
    public static void main(String[] args) throws Exception {
        if(Desktop.isDesktopSupported()) {
            Desktop dsktop = Desktop.getDesktop();
            if(dsktop.isSupported(Desktop.Action.BROWSE)) {
                dsktop.browse(new URI("http://www.eksperten.dk/"));
            }
        }
    }
}

I think it is very useful.

And I expect it to be used - assuming that people become aware of the feature.

Article history:

Version Date Description
1.0 March 26th 2006 Initial version (in Danish) published on Eksperten.dk
1.1 March 27th 2006 Add desktop example
1.3 July 4th 2006 Beta 1 to beta 2 changes
1.5 March 21st 2008 Modify JC16 example
2.0 August 6th 2016 Translation to English and complete reformatting and publishing here
2.1 October 8th 2016 Add content overview
2.2 May 22nd 2018 Remove SQL annotations section that did not make it into JDBC 4.0
2.2 March 23rd 2017 Add release dates

Other articles:

See list of all articles here

Comments:

Please send comments to Arne Vajhøj