Java 1.7/7 New Features

Content:

  1. Version numbers
  2. Release
  3. Number literals
  4. Switch on strings
  5. Type inference for generic constructors
  6. Multi catch
  7. Try with resource
  8. IO utility methods
  9. Fork Join
  10. URLClassLoader
  11. JDBC
  12. Better support dynamic languages
  13. JavaDoc

Version numbers:

This version is officially known as Java SE 7, but often called Java 1.7. It has codename Dolphin.

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
1.7/7 Java SE 7 Dolphin July 7th 2011

Release:

Java 1.7 was released July 7th 2011.

Java 1.7 was delayed multiple times (among other reasons because Oracle acquired Sun in the middle of development) so it took four and half year to get from Java 1.6 to Java 1.7.

Even though it took a long time, then the changes are relative small. Several of the changes are clearly inspired by C# and .NET.

Number literals:

Java 1.7 allows binary literals and underscore in numbers to make them more readable.

Previous:

public class Lit16 {
    public static void main(String[] args) {
        int v1 = 0x03030303;
        System.out.println(Integer.toString(v1, 2));
        int v2 = 123456789;
        System.out.println(v2);
    }
}

Now:

public class Lit17 {
    public static void main(String[] args) {
        int v1 = 0b00000011000000110000001100000011;
        System.out.println(Integer.toString(v1, 2));
        int v2 = 123_456_789;
        System.out.println(v2);
    }
}

I think it is useful but not really important.

I don't think any of these will be used much.

Switch on strings

Java 1.7 allows switch on strings.

Previous:

public class StrSwi16 {
    public static void test(String s) {
        if(s.equals("AA")) {
            System.out.println("called with AA");
        } else if(s.equals("BB")) {
            System.out.println("called with BB");
        } else {
            System.out.println("Called with something else");
        }
    }
    public static void main(String[] args) {
        test("BB");
    }
}

Now:

public class StrSwi17 {
    public static void test(String s) {
        switch(s) {
            case "AA":
                System.out.println("called with AA");
                break;
            case "BB":
                System.out.println("called with BB");
                break;
            default:
                System.out.println("Called with something else");
                break;
        }
    }
    public static void main(String[] args) {
        test("BB");
    }
}

It is very practical and many other languages including C# has this ability.

I expect this to be used alot.

Type inference for generic constructors:

Java 1.7 allow the usage of <> for constructors if Java can infere which type(s) to use.

<> is often called the diamond operator.

Previous:

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;

public class GenCon16 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        Map<String,String> map = new HashMap<String,String>();
    }
}

Now:

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;

public class GenCon17 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        Map<String,String> map = new HashMap<>();
    }
}

Practical little feature but not important.

It will be used.

Multi catch:

Java 1.7 allows catching multiple exception types in a single catch.

Previous:

public class MulCat16 {
    public static void test() throws SomeException, SomeOtherException {
        throw new SomeOtherException();
    }
    public static void main(String[] args) {
        try {
            test();
        } catch(SomeException ex) {
            ex.printStackTrace();
        } catch(SomeOtherException ex) {
            ex.printStackTrace();
        }
    }
}

class SomeException extends Exception {
}

class SomeOtherException extends Exception {
}

Now:

public class MulCat17 {
    public static void test() throws SomeException, SomeOtherException {
        throw new SomeOtherException();
    }
    public static void main(String[] args) {
        try {
            test();
        } catch(SomeException|SomeOtherException ex) {
            ex.printStackTrace();
        }
    }
}

class SomeException extends Exception {
}

class SomeOtherException extends Exception {
}

Practical little feature but not important.

It will be used.

Try with resource:

Java 1.7 makes it possible to get close called automatically whether normal flow or exception.

Same concept as using blocks in C# and VB.NET - just sligtly different implemented.

First some standard Java IO code.

Previous:

import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;

public class TryResStd16 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader("java17.txt"));
            String line;
            while((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } finally {
            if(br != null) {
                br.close();
            }
        }
    }
}

Now:

import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;

public class TryResStd17 {
    public static void main(String[] args) throws IOException {
        try (BufferedReader br = new BufferedReader(new FileReader("java17.txt"))) {
            String line;
            while((line = br.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
}

Obviously the same is possible for ones own classes. Just implement the AutoCloseable interface.

Example:

public class TryResCus17 {
    public static void main(String[] args) throws Exception {
        try (MyRes r = new MyRes(false)) {
            r.test();
        }
        try (MyRes r = new MyRes(true)) {
            r.test();
        }
    }
}

class MyRes implements AutoCloseable {
    private boolean willthrow;
    public MyRes(boolean willthrow) {
        this.willthrow = willthrow;
        System.out.println("constuctor called");
    }
    public void test() throws Exception {
        if(willthrow) {
            throw new Exception("Ooops");
        }
    }
    public void close() {
        System.out.println("close called");
    }
}

There are some possible coomplications due to:

This example shows how everything fit together:

public class TryResTricky17 {
    public static void main(String[] args) throws Exception {
        try (MyRes r = new MyRes()) {
            r.test();
        } catch(Exception ex) {
            System.out.println("catch of: " + ex.getMessage());
            for(Throwable t : ex.getSuppressed()) {
                System.out.println("suppressed: " + t.getMessage());
            }
        } finally {
            System.out.println("traditional finally");
        }
    }
}

class MyRes implements AutoCloseable {
    public MyRes() {
        System.out.println("constuctor called");
    }
    public void test() throws Exception {
        System.out.println("test called - will throw exception");
        throw new Exception("exception in test");
    }
    public void close() throws Exception {
        System.out.println("close called - will throw exception");
        throw new Exception("exception in close");
    }
}
constuctor called
test called - will throw exception
close called - will throw exception
catch of: exception in test
suppressed: exception in close
traditional finally

I think it is a very useful feature.

I think it will take some time for people to get used to it, but after some time I think it will become popular.

IO utility methods:

Java 1.7 got some utility methods making it easier to do various trivial file operations.

Very similar to VB and .NET.

Reading and writing files.

Before:

import java.io.InputStream;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintWriter;
import java.io.FileWriter;
import java.io.File;
import java.io.IOException;

public class Files16 {
    public static void main(String[] args) throws IOException {
        // binary
        InputStream is = new FileInputStream("java17.txt");
        OutputStream os = new FileOutputStream("z.txt");
        byte[] buf = new byte[1000];
        int n;
        while((n = is.read(buf, 0, buf.length)) > 0) {
            os.write(buf, 0, n);
        }
        os.close();
        is.close();
        (new File("z.txt")).delete();
        // text
        BufferedReader br = new BufferedReader(new FileReader("java17.txt"));
        PrintWriter pw = new PrintWriter(new FileWriter("z.txt"));
        String line;
        while((line = br.readLine()) != null) {
            pw.println(line);
        }
        pw.close();
        br.close();
        (new File("z.txt")).delete();
    }
}

Now:

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;

public class Files17 {
    public static void main(String[] args) throws IOException {
        Path from = Paths.get("java17.txt");
        Path to = Paths.get("z.txt");
        // binary
        Files.write(to, Files.readAllBytes(from));
        Files.delete(to);
        // text
        Files.write(to, Files.readAllLines(from, Charset.forName("ISO-8859-1")), Charset.forName("ISO-8859-1"));
        Files.delete(to);
        // lazy
        Files.copy(from, to);
        Files.delete(to);
    }
}

Advanced functions on file system:

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;

public class FS17 {
    public static void main(String[] args) throws IOException {
        Path f = Paths.get("java17.txt");
        System.out.println(Files.getOwner(f));
        System.out.println(Files.isReadable(f));
        System.out.println(Files.isWritable(f));
        System.out.println(Files.readAttributes(f, "*"));
        System.out.println(Files.getFileStore(f).getUnallocatedSpace() + "/" + Files.getFileStore(f).getTotalSpace());
    }
}

I think it is very useful additions.

And I am sure that they will be used, when people learn about them.

Fork Join:

Java 1.6 got the package java.util.concurrent with several classes making multi-threaded programming easier. Java 1.7 has added the Fork Join framework to this package.

Fork Join is a framework for solving tasks in parallel via divide and conquer.

Previous:

public class FJ16 {
    private int val;
    private int start;
    private int end;
    public FJ16(int val, int start, int end) {
        this.val = val;
        this.start = start;
        this.end = end;
    }
    public int countMultipla() {
        int res = 0;
        for(int i = start; i <= end; i++) {
            if(i % val == 0) {
                res++;
            }
        }
        return res;
    }
    public static void main(String[] args) {
        long t1 = System.currentTimeMillis();
        FJ16 o = new FJ16(4, 1, 1000000000);
        int n = o.countMultipla();
        long t2 = System.currentTimeMillis();
        System.out.println(n + " in " + (t2 - t1));
    }
}

Now:

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

public class FJ17 extends RecursiveTask<Integer> {
    private int val;
    private int start;
    private int end;
    public FJ17(int val, int start, int end) {
        this.val = val;
        this.start = start;
        this.end = end;
    }
    public int countMultipla() {
        int res = 0;
        for(int i = start; i <= end; i++) {
            if(i % val == 0) {
                res++;
            }
        }
        return res;
    }
    @Override
    public Integer compute() {
        int n = end - start + 1;
        if(n < 10_000_000) {
            return countMultipla();
        } else {
            FJ17 low = new FJ17(val, start, start + n/2);
            FJ17 high = new FJ17(val, start+n/2+1, end);
            // do not use:
            //invokeAll(low, high);
            //return low.join() + high.join();
            // use:
            high.fork();
            return low.compute() + high.join();
        }
    }
    public static void main(String[] args) {
        ForkJoinPool fjp = new ForkJoinPool(8);
        long t1 = System.currentTimeMillis();
        FJ17 o = new FJ17(4, 1, 1_000_000_000);
        fjp.invoke(o);
        int n = o.join();
        long t2 = System.currentTimeMillis();
        System.out.println(n + " in " + (t2 - t1));
    }
}

As can be seen then parallelization via fork join actually increases the amount of code.

But runtime on my PC was reduced from 4626 ms to 1174 ms, which is almost a perfect reduction to 1/4 on a quad core CPU.

Note that the ParallelArray class has been postponed to Java 8, because lambda expressions has been postponed to Java 8. The ParallelArray class would have significantly reduced the amount of code needed.

If you can't wait for ParallelArray then here is an implemenation.

Single threaded:

public class PA16 {
    public static void addOneToAll(int[] a) {
        for(int i = 0; i < a.length; i++) {
            a[i] = a[i] + 1;
        }
    }
    public static void main(String[] args) {
        int[] a = new int[1000];
        for(int i = 0; i < a.length; i++) {
            a[i] = i + 1;
        }
        addOneToAll(a);
        System.out.println(a[0] + " " + a[a.length - 1]);
    }
}

Multi threaded via Fork Join:

public interface Applier<T> {
    void applyToElement(T[] a, int ix);
}
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;

public class ParallelArray<T> {
    public static class ParallelArrayApplier<T> extends RecursiveAction {
        private T[] a;
        private int start;
        private int end;
        private Applier<T> app;
        public ParallelArrayApplier(T[] a, int start, int end, Applier<T> app) {
            this.a = a;
            this.start = start;
            this.end = end;
            this.app = app;
        }
        @Override
        public void compute() {
            int n = end - start + 1;
            if(n < 100) {
                for(int i = start; i <= end; i++) {
                    app.applyToElement(a, i);
                }
            } else {
                ParallelArrayApplier<T> low = new ParallelArrayApplier<T>(a, start, start + n/2, app);
                ParallelArrayApplier<T> high = new ParallelArrayApplier<T>(a, start+n/2+1, end, app);
                high.fork();
                low.compute();
                high.join();
            }
        }
    }
    private ForkJoinPool fjp;
    private T[] a;
    public ParallelArray(ForkJoinPool fjp, T[] a) {
        this.fjp = fjp;
        this.a = a;
    }
    public void apply(Applier<T> app) {
        ParallelArrayApplier<T> paa = new ParallelArrayApplier<T>(a, 0, a.length-1, app);
        fjp.invoke(paa);
        paa.join();
    }
}
import java.util.concurrent.ForkJoinPool;

public class PA17 {
    private static ForkJoinPool fjp = new ForkJoinPool(8);
    public static void addOneToAll(Integer[] a) {
        ParallelArray<Integer> pa = new ParallelArray<>(fjp, a);
        pa.apply(new Applier<Integer>() {
            public void applyToElement(Integer[] a, int ix) {
                a[ix] = a[ix] + 1;
            }
        });
    }
    public static void main(String[] args) {
        Integer[] a = new Integer[1000];
        for(int i = 0; i < a.length; i++) {
            a[i] = i + 1;
        }
        addOneToAll(a);
        System.out.println(a[0] + " " + a[a.length - 1]);
    }
}

The code can probably be improved, but it is a starting point.

UPDATE: ParallelArray did not make it into Java 8 either. Instead Java 8 got some predefined parallel* methods in the Arrays class and a much more general stream concept.

I think Fork Join is a really cool framework, but it will become more useful in Java 8.

I expect Fork Join to see some usage.

UPDATE: Java 8 parallel stream has taken away a lot of the potential usage for Fork Join. Now Fork Join is only relevant for more custom code.

URLClassLoader:

URLClassLoader has got a close method that:

JDBC:

JDBC has been updated from 4.0 to 4.1.

The biggest change is support for try with resource (see above) for Connection, Statement/PreparedStatement/CallableStatement and ResultSet.

Better support dynamic languages:

1.7 JVM has better support for programming langauges with dynamic types like JRuby and JPython.

These languages are raising in popularity on the Java platform, so it is an important enhancement.

JavaDoc:

Design of JavaDoc has been updated.

This is obviously cosmetic only, but it is highly visible.

Article history:

Version Date Description
1.0 July 17th 2011 Initial version (in Danish) published on Eksperten.dk
1.1 July 30th 2011 Add ForkJoin and JavaDoc
2.0 August 5th 2016 Translation to English and complete reformatting and publishing here
2.1 October 8th 2016 Add content overview
2.2 March 23rd 2017 Add release dates

Other articles:

See list of all articles here

Comments:

Please send comments to Arne Vajhøj