Java 7 at SoftShake 2011

Preview:

Citation preview

Java SE 7Julien Ponge

Fork / Join

Project Coin

NIO.2

invokedynamic

(...)

Fork / Join

synchronized

wait()notify()< 5

java.lang.Threadjava.lang.Runnable

Thread thread = new Thread() { public void run() { System.out.println(">>> Hello!"); }}; thread.start();thread.join();

java.util.concurrent

executorsconcurrent queuesconcurrent collectionsatomic variablessynchronization patternsrich locks

5, 6

class Sum implements Callable<Long> { private final long from; private final long to; Sum(long from, long to) { this.from = from; this.to = to; } public Long call() { long acc = 0; for (long i = from; i <= to; i++) { acc = acc + i; } return acc; } }

ExecutorService executor = Executors.newFixedThreadPool(2);

List<Future<Long>> results = executor.invokeAll(asList( new Sum(0, 10), new Sum(100, 1000), new Sum(10000, 1000000)));

for (Future<Long> result : results) { System.out.println(result.get());}

Threads made easy

Concurrency made easier

Parallelism made easier

1.01.11.21.31.4

56

7

n1 n2 n3 n4 n5 n6 n8n7 n9 ... ... ......

sum1 sum2 sum3sum1 + sum2 sum3 + (...)

total sum

Sum of an array

How many occurrences of “java.util.List” in this filesystem tree?

Load into RAM (1 thread)

subfolders: List<Folder>documents: List<Document>

Folderlines: List<String>

Document

Divide & conquer (#cores threads)

SplitFork subtasksJoin subtasksCompose results

Thread managementMaximize parallelism

Work stealing

Your workForkJoinPool

Child ForkJoinTask

fork() fork()join() join()

Child ForkJoinTask

ForkJoinTask

RecursiveActionvs

RecursiveTask

Document wordcounting task

Document wordcounting task

Folder wordcounting task

Folder wordcounting task

Document wordcounting task

Document wordcounting task

3

n

2

51

10

16

fork()

join()

(F/J demo)

1"

2"

3"

4"

5"

6"

7"

2" 4" 6" 8" 10" 12"

Speedup&

#cores

No I/ONo synchronization / locks

Decompose in simple recursive tasksDo not decompose below a threshold

Take advantage of multicores with no pain

You have more F/J candidate algorithms than you think!

try-with-resources

private void writeSomeData() throws IOException { DataOutputStream out = new DataOutputStream(new FileOutputStream("data")); out.writeInt(666); out.writeUTF("Hello"); out.close();}

private void writeSomeData() throws IOException { DataOutputStream out = new DataOutputStream(new FileOutputStream("data")); out.writeInt(666); out.writeUTF("Hello"); out.close();}

what if...

private void writeSomeData() throws IOException { DataOutputStream out = null; try { out = new DataOutputStream(new FileOutputStream("data")); out.writeInt(666); out.writeUTF("Hello"); } finally { if (out != null) { out.close(); } } }

private void writeSomeData() throws IOException { DataOutputStream out = null; try { out = new DataOutputStream(new FileOutputStream("data")); out.writeInt(666); out.writeUTF("Hello"); } finally { if (out != null) { out.close(); } } }

...this is still far from correct!

try (

FileOutputStream out = new FileOutputStream("output"); FileInputStream in1 = new FileInputStream(“input1”); FileInputStream in2 = new FileInputStream(“input2”)

) {

// Do something useful with those 3 streams! // out, in1 and in2 will be closed in any case

out.write(in1.read()); out.write(in2.read());}

public class AutoClose implements AutoCloseable { @Override public void close() { System.out.println(">>> close()"); throw new RuntimeException("Exception in close()"); } public void work() throws MyException { System.out.println(">>> work()"); throw new MyException("Exception in work()"); }}

AutoClose autoClose = new AutoClose();try { autoClose.work();} finally { autoClose.close();}

AutoClose autoClose = new AutoClose();try { autoClose.work();} finally { autoClose.close();}

>>> work() >>> close() java.lang.RuntimeException: Exception in close()        at AutoClose.close(AutoClose.java:6)        at AutoClose.runWithMasking(AutoClose.java:19)        at AutoClose.main(AutoClose.java:52)

AutoClose autoClose = new AutoClose();try { autoClose.work();} finally { autoClose.close();}

>>> work() >>> close() java.lang.RuntimeException: Exception in close()        at AutoClose.close(AutoClose.java:6)        at AutoClose.runWithMasking(AutoClose.java:19)        at AutoClose.main(AutoClose.java:52)

MyException masked by RuntimeException

“Caused by” ≠ “Also happened”

AutoClose autoClose = new AutoClose();MyException myException = null;try { autoClose.work();} catch (MyException e) { myException = e; throw e;} finally { if (myException != null) { try { autoClose.close(); } catch (Throwable t) { myException.addSuppressed(t); } } else { autoClose.close(); }}

AutoClose autoClose = new AutoClose();MyException myException = null;try { autoClose.work();} catch (MyException e) { myException = e; throw e;} finally { if (myException != null) { try { autoClose.close(); } catch (Throwable t) { myException.addSuppressed(t); } } else { autoClose.close(); }}

AutoClose autoClose = new AutoClose();MyException myException = null;try { autoClose.work();} catch (MyException e) { myException = e; throw e;} finally { if (myException != null) { try { autoClose.close(); } catch (Throwable t) { myException.addSuppressed(t); } } else { autoClose.close(); }}

AutoClose autoClose = new AutoClose();MyException myException = null;try { autoClose.work();} catch (MyException e) { myException = e; throw e;} finally { if (myException != null) { try { autoClose.close(); } catch (Throwable t) { myException.addSuppressed(t); } } else { autoClose.close(); }}

AutoClose autoClose = new AutoClose();MyException myException = null;try { autoClose.work();} catch (MyException e) { myException = e; throw e;} finally { if (myException != null) { try { autoClose.close(); } catch (Throwable t) { myException.addSuppressed(t); } } else { autoClose.close(); }}

try (AutoClose autoClose = new AutoClose()) { autoClose.work();}

try (AutoClose autoClose = new AutoClose()) { autoClose.work();}

>>> work() >>> close() MyException: Exception in work()        at AutoClose.work(AutoClose.java:11)        at AutoClose.main(AutoClose.java:16)        Suppressed: java.lang.RuntimeException: Exception in close()               at AutoClose.close(AutoClose.java:6)               at AutoClose.main(AutoClose.java:17)

public void compress(String input, String output) throws IOException { try( FileInputStream fin = new FileInputStream(input); FileOutputStream fout = new FileOutputStream(output); GZIPOutputStream out = new GZIPOutputStream(fout) ) { byte[] buffer = new byte[4096]; int nread = 0; while ((nread = fin.read(buffer)) != -1) { out.write(buffer, 0, nread); } }}

public void compress(String paramString1, String paramString2)         throws IOException {     FileInputStream localFileInputStream = new FileInputStream(paramString1);    Object localObject1 = null;     try {         FileOutputStream localFileOutputStream = new FileOutputStream(paramString2);        Object localObject2 = null;         try {             GZIPOutputStream localGZIPOutputStream = new GZIPOutputStream(localFileOutputStream);            Object localObject3 = null;             try {                 byte[] arrayOfByte = new byte[4096];                 int i = 0;                 while ((i = localFileInputStream.read(arrayOfByte)) != -1) {                     localGZIPOutputStream.write(arrayOfByte, 0, i);                 }             } catch (Throwable localThrowable6) {                 localObject3 = localThrowable6;                 throw localThrowable6;             } finally {                 if (localGZIPOutputStream != null) {                     if (localObject3 != null) {                         try {                             localGZIPOutputStream.close();                         } catch (Throwable localThrowable7) {                             localObject3.addSuppressed(localThrowable7);                         }                     } else {                         localGZIPOutputStream.close();                     }                 }             }         } catch (Throwable localThrowable4) {             localObject2 = localThrowable4;             throw localThrowable4;         } finally {             if (localFileOutputStream != null) {                 if (localObject2 != null) {                     try {                         localFileOutputStream.close();                     } catch (Throwable localThrowable8) {                         localObject2.addSuppressed(localThrowable8);                     }                 } else {                     localFileOutputStream.close();                 }             }         }     } catch (Throwable localThrowable2) {         localObject1 = localThrowable2;         throw localThrowable2;     } finally {         if (localFileInputStream != null) {             if (localObject1 != null) {                 try {                     localFileInputStream.close();                 } catch (Throwable localThrowable9) {                     localObject1.addSuppressed(localThrowable9);                 }             } else {                 localFileInputStream.close();             }         }     } }

public void compress(String input, String output) throws IOException { try( FileInputStream fin = new FileInputStream(input); FileOutputStream fout = new FileOutputStream(output); GZIPOutputStream out = new GZIPOutputStream(fout) ) { byte[] buffer = new byte[4096]; int nread = 0; while ((nread = fin.read(buffer)) != -1) { out.write(buffer, 0, nread); } }}

Not just syntactic sugarClutter-free, correct code

close(): - be more specific than java.lang.Exception - no exception if it can’t fail - no exception that shall not be suppressed (e.g., java.lang.InterruptedException)

Diamond <>

List<String> strings = new LinkedList<Integer>();

Map<String, List<String>> contacts = new HashMap<Integer, String>();

List<String> strings = new LinkedList<String>();strings.add("hello");strings.add("world");

Map<String, List<String>> contacts = new HashMap<String, List<String>>();contacts.put("Julien", new LinkedList<String>());contacts.get("Julien").addAll(asList("Foo", "Bar", "Baz"));

List<String> strings = new LinkedList<>();strings.add("hello");strings.add("world");

Map<String, List<String>> contacts = new HashMap<>();contacts.put("Julien", new LinkedList<String>());contacts.get("Julien").addAll(asList("Foo", "Bar", "Baz"));

Map<String, String> map = new HashMap<String, String>() { { put("foo", "bar"); put("bar", "baz"); }};

Map<String, String> map = new HashMap<>() { { put("foo", "bar"); put("bar", "baz"); }};

Map<String, String> map = new HashMap<>() { { put("foo", "bar"); put("bar", "baz"); }};

Diamond.java:43: error: cannot infer type arguments for HashMap; Map<String, String> map = new HashMap<>() { ^ reason: cannot use '<>' with anonymous inner classes1 error

class SomeClass<T extends Serializable & CharSequence> { }

Non-denotable type

class SomeClass<T extends Serializable & CharSequence> { }

Non-denotable type

SomeClass<?> foo = new SomeClass<String>();SomeClass<?> fooInner = new SomeClass<String>() { };

SomeClass<?> bar = new SomeClass<>();

SomeClass<?> bar = new SomeClass<>() { };

class SomeClass<T extends Serializable & CharSequence> { }

Non-denotable type

SomeClass<?> foo = new SomeClass<String>();SomeClass<?> fooInner = new SomeClass<String>() { };

SomeClass<?> bar = new SomeClass<>();

SomeClass<?> bar = new SomeClass<>() { };

No denotable typeto generate a class

Less ceremony when using generics

No diamond with inner classes

Simplified varargs

private static <T> void doSomethingBad(List<T> list, T... values) { values[0] = list.get(0);}

public static void main(String[] args) { List list = Arrays.asList("foo", "bar", "baz"); doSomethingBad(list, 1, 2, 3);}

private static <T> void doSomethingBad(List<T> list, T... values) { values[0] = list.get(0);}

public static void main(String[] args) { List list = Arrays.asList("foo", "bar", "baz"); doSomethingBad(list, 1, 2, 3);}

Heap Pollution: List = List<String>

This yields warnings + crash:

private static <T> void doSomethingGood(List<T> list, T... values) { for (T value : values) { list.add(value); }}

private static <T> void doSomethingGood(List<T> list, T... values) { for (T value : values) { list.add(value); }}

$ javac Good.java Note: Good.java uses unchecked or unsafe operations.Note: Recompile with -Xlint:unchecked for details.

@SuppressWarnings({“unchecked”,“varargs”})

public static void main(String[] args) { List<String> list = new LinkedList<>(); doSomethingGood(list, "hi", "there", "!");}

$ javac Good.java $

@SafeVarargsprivate static <T> void doSomethingGood(List<T> list, T... values) { for (T value : values) { list.add(value); }}

static, final methods, constructors

Mark your code as safe for varargs

You can’t cheat with @SafeVarags

Remove @SuppressWarnings in client code and pay attention to real warnings

Multi-catch & more precise rethrow

Class<?> stringClass = Class.forName("java.lang.String"); Object instance = stringClass.newInstance(); Method toStringMethod = stringClass.getMethod("toString"); System.out.println(toStringMethod.invoke(instance));

try { Class<?> stringClass = Class.forName("java.lang.String"); Object instance = stringClass.newInstance(); Method toStringMethod = stringClass.getMethod("toString"); System.out.println(toStringMethod.invoke(instance));} catch (ClassNotFoundException e) { e.printStackTrace();} catch (InstantiationException e) { e.printStackTrace();} catch (IllegalAccessException e) { e.printStackTrace();} catch (NoSuchMethodException e) { e.printStackTrace();} catch (InvocationTargetException e) { e.printStackTrace();}

try { Class<?> stringClass = Class.forName("java.lang.String"); Object instance = stringClass.newInstance(); Method toStringMethod = stringClass.getMethod("toString"); System.out.println(toStringMethod.invoke(instance));} catch (Throwable t) { t.printStackTrace();}

try { Class<?> stringClass = Class.forName("java.lang.String"); Object instance = stringClass.newInstance(); Method toStringMethod = stringClass.getMethod("toString"); System.out.println(toStringMethod.invoke(instance));} catch (Throwable t) { t.printStackTrace();}

How about SecurityException?

try { Class<?> stringClass = Class.forName("java.lang.String"); Object instance = stringClass.newInstance(); Method toStringMethod = stringClass.getMethod("toString"); System.out.println(toStringMethod.invoke(instance));} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { e.printStackTrace();}

Union of alternatives

catch (SomeException e)

Now implicitly final unless assigned...

static class SomeRootException extends Exception { }static class SomeChildException extends SomeRootException { }static class SomeOtherChildException extends SomeRootException { }

public static void main(String... args) throws Throwable {try { throw new SomeChildException();} catch (SomeRootException firstException) { try { throw firstException; } catch (SomeOtherChildException secondException) { System.out.println("I got you!"); }}

static class SomeRootException extends Exception { }static class SomeChildException extends SomeRootException { }static class SomeOtherChildException extends SomeRootException { }

public static void main(String... args) throws Throwable {try { throw new SomeChildException();} catch (SomeRootException firstException) { try { throw firstException; } catch (SomeOtherChildException secondException) { System.out.println("I got you!"); }}

$ javac Imprecise.java Imprecise.java:13: error: exception SomeOtherChildException is never thrown in body of corresponding try statement } catch (SomeOtherChildException secondException) { ^1 error

Less clutterBe preciseDo not capture unintended exceptions

Better exception flow analysis

Minor additions

// 123 in decimal, octal, hexadecimal and binarybyte decimal = 123;byte octal = 0_173;byte hexadecimal = 0x7b;byte binary = 0b0111_1011;

// Other valuesdouble doubleValue = 1.111_222_444F;long longValue = 1_234_567_898L;long longHexa = 0x1234_3b3b_0123_cdefL;

public static boolean isTrue(String str) { switch(str.trim().toUpperCase()) { case "OK": case "YES": case "TRUE": return true;

case "KO": case "NO": case "FALSE": return false;

default: throw new IllegalArgumentException("Not a valid true/false string."); } }

public static boolean isTrue(String s) { String str = s.trim().toUpperCase(); int jump = -1; switch(str.hashCode()) { case 2404: if (str.equals("KO")) { jump = 3; } break;(...) switch(jump) {(...) case 3: case 4: case 5: return false; default: throw new IllegalArgumentException( "Not a valid true/false string."); }}

Bucket

Real code

Fork and Join: Java Can Excel at Painless Parallel Programming Too!

Better Resource Management withJava SE 7: Beyond Syntactic Sugar

Oracle Technology Network

http://goo.gl/tostz

http://goo.gl/7ybgr

(more soon...)

Julien Ponge

@jponge

http://gplus.to/jponge

http://julien.ponge.info/

julien.ponge@insa-lyon.fr