What’s New in Java SE 7? - · PDF fileJava SE 7 • Java SE 7 released on July 28,...

53
What’s New in Java SE 7? Kirk Spadt - kspadt 0x40 afsvision.com Principal Architect Automated Financial Systems, Inc. http://www.afsvision.com Java SE 7 Released July 28, 2011 Oracle Corporation http://download.oracle.com/javase/7/docs/api

Transcript of What’s New in Java SE 7? - · PDF fileJava SE 7 • Java SE 7 released on July 28,...

What’s New in Java SE 7?

Kirk Spadt - kspadt 0x40 afsvision.comPrincipal ArchitectAutomated Financial Systems, Inc.http://www.afsvision.com

Java SE 7Released July 28, 2011

Oracle Corporationhttp://download.oracle.com/javase/7/docs/api

What’s New in Java SE 7? – Copyright Notice

• Slides and examples are copyrighted material.– Copyright © 2011 Kirk B. Spadt, except where noted– The examples are original works covered under this copyright

• Permission is granted by the author to use these slides:– These slides can be utilized in your presentation – in full or in part– Provided that this copyright notice remains intact– This notice must precede all included slides and be clearly visible– Additional copyright notices may be appended to this slide

Java SE 7

• Java SE 7 released on July 28, 2011– First major release of Java since Oracle acquired Sun– First maintenance release, jdk-7u1, released 10/18/2011

• Almost 5 years in the making– 55 months since Java SE 6

– Evolutionary – incremental changes only

– Major features were deferred to Java SE 8 (due end 2012)

• Components of Java SE 7 (specified in JSR-336)– Java language changes - Project Coin – JSR-334– Enhanced platform file I/O support – JSR-203– Fork-Join framework for parallel processing – JSR-166– JVM based language support: InvokeDynamic – JSR-292– Miscellaneous class and library enhancements

Java SE Release Statistics

Java Language Changes – Project Coin

• Numeric literals: Grouping separators and binary literals• Switch-Case statements for String literals• Generic “diamond” operator – less redundant constructors• Multiple exceptions handled per catch block• Automatic resource closing – try-with-resources block

• Stack traces now contain suppressed finally {} exceptions

Numeric Literals – Old

/** Numeric literal. */

public static final long OLD_TEN_MILLION = 10000000L;

/** Fractional literal (should use 1.0e-12). */

public static final double OLD_PICO = 0.000000000001;

/** An int as a binary bitmap literal. */

public static final int OLD_STATUS = 0x0813;

Numeric Literals – Old + New

/** Numeric literal. */

public static final long OLD_TEN_MILLION = 10000000L;

public static final long NEW_TEN_MILLION = 10_000_000L;

/** Fractional literal (should use 1.0e-12). */

public static final double OLD_PICO = 0.000000000001;

public static final double NEW_PICO = 0.000_000_000_001;

/** Binary literal. */

public static final int OLD_STATUS = 0x0813;

public static final int NEW_STATUS = 0b0000100000010011;

public static final int ALT_STATUS = 0b0000_1000_0001_0011;

String Comparisons - Old

/** Assigns a value to a field based on key – String Compares. */

public void oldAssignAttr(String key, String image) {

if ("name".equals(key)) {

name = image;

} else if ("text".equals(key) || “descr".equals(key)) {

text = image;

} else {

throw new IllegalArgumentException("key=" + key);

}

}

String Comparisons - New

/** Assigns a value to a field based on key - String switch. */

public void newAssignAttr(String key, String image) {

switch (key) {

case "name":

name = image;

break;

case "text":

case “descr":

text = image;

break;

default:

throw new IllegalArgumentException("key=" + key);

}

}

String Switch - Observations

• Switch/Case statement is now valid for Strings• String comparison is case-sensitive• String switch is ~41% faster than if-else comparisons

– Simple test: comparison/assignment among 5 values (2.0 GHz pc)– String if-else: 22.68 ns– String switch-case: 16.09 ns– Enum switch-case: 10.57 ns– Int switch-case: 6.42 ns

Generic Constructors - Old

/** Instantiate a map using Java 1.5 generic parameterization. */

public Map<String, Map<Integer, List<String>>> oldMap

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

Duplicate generic parameter declaration is extra work, increases noise and decreases clarity.

Generic Constructors – Old + New

/** Instantiate a map using Java 1.5 generic parameterization. */

public Map<String, Map<Integer, List<String>>> oldMap

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

/** Instantiate a map using the java 1.7 diamond operator. */

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

Diamond operator replaces the duplicate declaration, and is explicitly required.

Generic Constructors - Observations

• Diamond operator <> denotes constructor type inference• Eliminates duplicate generic parameter declaration• Requires developer to explicitly declare intent.• Omitting diamond operator still results in compiler warning:

“HashMap is a raw type. References to generic type HashMap<K,V> should be parameterized.”

Generic Constructors – Pre Java 7 Alternate

/** Instantiate using method-level type inference in Java 1.5. */

Map<String, List<Map.Entry<String, int[]>>> altMap = New.hashMap();

/** Static factory methods - return generically-typed instances. */

public class New {

/** Returns a hash map generically typed to the lvalue's type. */

public static <K,V> Map<K, V> hashMap() {

return new HashMap<K, V>();

}

/** Returns an ArrayList generically typed to the lvalue's type. */

public static <E> List<E> arrayList() {

return new ArrayList<E>();

}

// . . . (More as needed)

Multiple Exceptions - Old

Code in multiple catch blocks is identical -- repetitive

/** Handle multiple exceptions with individual catch blocks. */

public void oldExecuteMethod(Object target, String methodName) {

try {

Method method = target.getClass().getMethod(methodName);

method.invoke(target);

} catch (NoSuchMethodException e) {

throw new RuntimeException(String.format(EXE_MSG,

methodName, target.getClass().getName(), e.getMessage()), e);

} catch (IllegalAccessException e) {

throw new RuntimeException(String.format(EXE_MSG,

methodName, target.getClass().getName(), e.getMessage()), e);

} catch (InvocationTargetException e) {

throw new RuntimeException(String.format(EXE_MSG,

methodName, target.getClass().getName(), e.getMessage()), e);

}

}

/** Handle multiple exceptions with multiple catch blocks. */

public void newExecuteMethod(Object target, String methodName) {

try {

Method method = target.getClass().getMethod(methodName);

method.invoke(target);

} catch (NoSuchMethodException | IllegalAccessException

| InvocationTargetException e) {

throw new RuntimeException(String.format(EXE_MSG,

methodName, target.getClass().getName(), e.getMessage()), e);

}

}

Multiple Exceptions - New

Exception types separated by |s

Code in catch block is executed for any of the listed exception types

Multiple Exceptions – What type?

X

/** Identify how multiple exceptions are typed by the compiler. */

public void checkCommonExceptions(boolean batchErr, boolean dataErr) {

try {

OutputStream out = new FileOutputStream("out.txt");

Connection con = DriverManager.getConnection("jdbc:db2:dbname");

if (batchErr) throw new BatchUpdateException();

if (dataErr) throw new DataTruncation(0, false, true, 20, 16);

}

// Common superclass of these is SQLException, e is treated as such.

catch (BatchUpdateException | DataTruncation e) {

throw new RuntimeException(String.format(EXE_MSG,

e.getErrorCode(), e.getMessage()), e);

}

// Common superclass is Exception - SQLException.getErrorCode() fails

catch (IOException | SQLException e) {

throw new RuntimeException(String.format(EXE_MSG,

e.getErrorCode(), e.getMessage()), e);

}

}

Method applies to common superclass (SQLException)

Method is valid for SQLException but not for IOException

Multiple Exceptions - Observations

• Multiple exceptions can be specified in one catch block• The exception types are separated by | symbols• Eliminates writing and maintaining duplicate code • What is the effective type available in the catch block?

– The effective type is the common exception superclass

• Combine multiple exceptions in one catch block when:– The code needed to handle each exception is identical– All required exception methods are available in the superclass

Resource Management - Safe/** Read, write, and properly close using pre-Java 7 semantics. */public static void oldCopy(File inFile) { try { FileInputStream in = new FileInputStream(inFile); try { FailingOutput out = new FailingOutput(); try { byte[] buf = new byte[BUFSIZE]; int count; while ((count = in.read(buf)) > 0) { out.write(buf, 0, count); } } finally { out.close(); } } finally { in.close(); } } catch (IOException e) { e.printStackTrace(); }}

Creating resources that must be closed

Code that interacts with the resources

Code that assures open resources are properly closed

Exception handling

/** Read, write, and automatically close using managed resources. */public static void newCopy(File inFile) { try ( FileInputStream in = new FileInputStream(inFile); FailingOutput out = new FailingOutput(); ) { byte[] buf = new byte[BUFSIZE]; int count; while ((count = in.read(buf)) > 0) { out.write(buf, 0, count); } } catch (IOException e) { e.printStackTrace(); }}

Resource Management - New

Resources that must be closed – specified in ( .. )s before the { .They must implement AutoCloseable

Code that interacts with the resources

This pattern of use is called “try with resources”.

Code that assures open resources are properly closed is no longer required (no calls to close() exist above).

AutoCloseable resources specified in the try ( .. ) { are unconditionally closed as if a finally { .. } block existed.

Exception handling

No need for code that assures open resources are properly closed

/** Read, write, and automatically close using managed resources. */public static void newCopy(File inFile) throws IOException { try ( FileInputStream in = new FileInputStream(inFile); FailingOutput out = new FailingOutput(); ) { byte[] buf = new byte[BUFSIZE]; int count; while ((count = in.read(buf)) > 0) { out.write(buf, 0, count); } }}

Resource Management - New

Resources that must be closed – specified in ( .. )s before the { .They must implement AutoCloseable

Code that interacts with the resources

This pattern of use is called “try with resources”.

Code that assures open resources are properly closed is no longer required (no calls to close() exist above).

AutoCloseable resources specified in the try ( .. ) { are unconditionally closed as if a finally { .. } block existed.

No need for the catch block if your method is throwing the exception

No need for code that assures open resources are properly closed

Resource Management - Observations

• “Try with resources” automatically closes resources• Resources to be automatically managed (closed) are

specified in ( .. ) in the try line before the {• Managed resources must implement AutoCloseable: public interface AutoCloseable {

public void close() throws IOException;

}

• AutoCloseable and Closeable classes include:– Streams, Readers, Writers, JDBC, Channels, Sockets, etc.

• Compiler silently inserts close()s in nested finally blocks– Assures that open resources are closed when no errors occur– Assures that resources are closed when any error occurs– No null pointer on close() for resources that could not open– At runtime, the first error that occurred is thrown, not the last– Multiple errors that occur open closing are no longer lost

/** Read, write, and properly close using pre-Java 7 semantics. */public static void oldCopy(File inFile) { try { FileInputStream in = new FileInputStream(inFile); try { FailingOutput out = new FailingOutput(); try { byte[] buf = new byte[BUFSIZE]; int count; while ((count = in.read(buf)) > 0) { out.write(buf, 0, count); } } finally { out.close(); } } finally { in.close(); } } catch (IOException e) { e.printStackTrace(); }}

Resource Management – What Error?

If an error occurs during out.write(), and another error occurs during out.close(), which error “wins” (in the stack trace)?

C

B

E

D

F

A

Resource Management – What Error?

• Sample: Exception occurs in output write() and close():

/** A resource-managed class that fails upon write and close. */

public class FailingOutput implements AutoCloseable {

/** write() Always throws IOException. */

public int write(byte[] buf, int off, int len) throws IOException {

throw new IOException("Cannot write output");

}

/** close() always throws IOException (impls AutoCloseable). */

public void close() throws IOException {

throw new IOException("Cannot close output");

}

}

• Run a stack trace for try/finally and try-with-resources

Resource Management – Stack Traces

• (old) Close error after write error: nested try-finally blocks:java.io.IOException: Cannot close output

at com.spadt.demo.jdk7.io.FailingOutput.close(FailingOutput.java:15)

at com.spadt.demo.jdk7.example.C07_ExTraces.oldCopy(C07_ExTraces.java:33)

at com.spadt.demo.jdk7.example.C07_ExTraces.main(C07_ExTraces.java:63)

• (new) Close error after write error: Try with resources block:java.io.IOException: Cannot write output

at com.spadt.demo.jdk7.io.FailingOutput.write(FailingOutput.java:10)

at com.spadt.demo.jdk7.example.C07_ExTraces.newCopy(C07_ExTraces.java:50)

at com.spadt.demo.jdk7.example.C07_ExTraces.main(C07_ExTraces.java:66)

Suppressed: java.io.IOException: Cannot close output

at com.spadt.demo.jdk7.io.FailingOutput.close(FailingOutput.java:15)

at com.spadt.demo.jdk7.example.C07_ExTraces.newCopy(C07_ExTraces.java:52)

... 1 more

• Throwable.getSuppressedErrors() returns finally { .. } errors

New I/O 2 – Expanded I/O Support

• Three new packages in the new java.nio.file hierarchy• Path replaces File

– Better directory/file resolution; mime type discovery

– Implements Watchable – ability to detect file change events

• Files class – platform-specific file manipulation support– File copy, atomic move, access attributes, set permissions– Factory methods for streams, readers, writers, channels

– Fixes inconsistent implementations and error handling in java.io.*

• Directory iterators, tree recursion, and filtering• Filesystem support:

– E.g., FAT, ext3, zip archives, network filesystems, etc.– Symbolic link support– Access to file attributes (metadata)– SPI extensibility to implement new file systems

// Instantiate a path to a directory (this workspace)

Path ws = Paths.get("/var/eclipse/Jdk7Demo");

String expected = "\\var\\eclipse\\Jdk7Demo";

assertEquals(expected, ws.toString());

// Resolve a path relative to a given path.

Path pom = ws.resolve("demo.jdk7/pom.xml");

expected = "\\var\\eclipse\\Jdk7Demo\\demo.jdk7\\pom.xml";

assertEquals(expected, pom.toString());

// Recognizes equality at the physical file level.

Path proj = Paths.get("."); // (This project.)

assertTrue(Files.isSameFile(proj, pom.getParent()));

// Reads the file's attributes - including platform-specific ones.

assertEquals(Long.valueOf(895), Files.getAttribute(pom, "size"));

assertEquals(Boolean.FALSE, Files.getAttribute(pom, "dos:hidden"));

NIO-2: Paths and Attributes

// Copy a file in one line of code (verify copied file's length).Path pom = Paths.get("/var/eclipse/Jdk7Demo", "demo.jdk7/pom.xml");Path tmpPom = Paths.get("C:/tmp", "tmpPom.xml");Files.copy(pom, tmpPom, StandardCopyOption.REPLACE_EXISTING);assertEquals(Long.valueOf(895), Files.getAttribute(tmpPom, "size"));

// Move a file - platform-specific manner (unlike File.renameTo()).Path newPom = tmpPom.resolveSibling("newPom.xml");Files.move(tmpPom, newPom, StandardCopyOption.REPLACE_EXISTING);assertTrue(Files.exists(newPom));

// Read a text file into a list of strings (small files).Charset utf8 = Charset.forName("utf8");List<String> lines = Files.readAllLines(pom, utf8);assertEquals(" <artifactId>demo.jdk7</artifactId>", lines.get(3));

// Use one of the many factory methods for I/O resources.try ( Writer writer = Files.newBufferedWriter(newPom, utf8); ) { writer.write("<project></project>\n");}assertEquals(Long.valueOf(20), Files.getAttribute(newPom, "size"));

NIO-2: Files Class – Factories + Utilities

// Visit a directory recursively using a FileVisitor.final StringBuilder sb2 = new StringBuilder();

// Create the visitor, implementing visitFile().FileVisitor<Path> visitor = new SimpleFileVisitor<>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { String name = file.getFileName().toString(); if (name.contains("StringSwitch")) { sb2.append(file.getFileName()).append("; "); } return FileVisitResult.CONTINUE; }};

// Call the visitor, which recursively traverses the directory.Path javaSrc = Paths.get("src");Files.walkFileTree(javaSrc, visitor);String exp = "C02_StringSwitch.java; C03_StringSwitchTimings.java; ";assertEquals(exp, sb2.toString());

NIO-2: Directory VisitingYou implement visitFile() to select and work on files. You implement pre- and postVisitDirectory() to select directories.

You return values of FileVisitResult to control navigation, selection, and cancellation of the traversal.

Starts the recursive visiting.

/** Creates a watch service and responds to its events. */public void run() {

// Register a watch service on a directory. Path path = Paths.get("/tmp"); try ( WatchService ws = FileSystems.getDefault().newWatchService() ) { path.register(ws, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE); // Loop until interrupted. for (;;) { WatchKey key = ws.take(); for (WatchEvent<?> ev: key.pollEvents()) { eventLog.append(ev.kind() + ": " + ev.context() + "; "); } key.reset(); } } catch (IOException e) { throw new RuntimeException(e); } catch (InterruptedException e) { return; }}

NIO-2: Directory Watching

Key.reset() prepares for the next take().

Create a WatchService and request the /tmp directory to register its changes with it.

The ws.take() blocks until the directory changes. We iterate the WatchKey and log its events.

A thread interrupt will end the above loop.

Please note that paths are NOT watched recursively. Every directory being watched must be registered. However, add/delete of a child directory’s files will register a EVENT_MODIFY on the parent directory.

@Test public void monitorAndChangeDirectory() throws Exception { // Perform run() on a separate thread to capture file events. Thread thread = new Thread(this); thread.start(); // Perform some file operations in the tmp directory. Path pom = Paths.get("pom.xml"); Path tmp = Paths.get("/tmp/pom.tmp"); Thread.sleep(1000); Files.copy(pom, tmp, StandardCopyOption.REPLACE_EXISTING); Files.delete(tmp); Thread.sleep(1000);

// End the monitoring and check the results. thread.interrupt(); String expected = "ENTRY_CREATE: pom.tmp; ENTRY_MODIFY: pom.tmp; " + "ENTRY_MODIFY: pom.tmp; ENTRY_DELETE: pom.tmp; "; assertEquals(expected, eventLog.toString());}

NIO-2: Directory Watching Test

Fork-Join Framework

• Leverage multiple processors available to the JVM• Suitable for tasks that can be divided or broken down• Implementation of “divide and conquer” algorithm: If the work in my task is small enough

Execute the work in my task

else

Create some smaller tasks that do my work

Fork these tasks for available processors to run

Wait for and join the results

• Tasks get recursively divided until all are small enough• Similar in concept to Google Map/Reduce• Implementation leverages java.util.concurrent classes

Fork-Join Framework Classes

• ForkJoinTask – Divides up the work or executes it– You implement compute() to perform a task if it is small enough– If not, you create smaller instances of your ForkJoinTask subclass– You call invokeAll(ForkJoinTask task…) to execute those tasks– Subclass: RecursiveTask if a result value is to be returned– Subclass: RecursiveAction if no result value is required.

• ForkJoinPool – An ExecutorService implementation– Delegates work submitted to it to available processors– Uses a work-stealing algorithm to balance work among CPUs– Can utilize up to all processors - uses less resources than threads – Calling invoke(ForkJoinTask) starts dividing/executing of task

• Callable – A class that executes call() and returns a result– A collection of Callable instances can also be submitted to a pool

• Single-threaded AES encryption of lots of byte arrays:

– Each byte array is encrypted in sequence – one at a time

• AES encryption utilizing the Fork-Join framework

– Nested RecursiveAction subclasses wrap the arrays

– All the RecursiveAction instances are submitted to the pool

– Multiple byte arrays are encrypted simultaneously by each CPU

ForkJoinPool

Fork-Join Framework Example

byte[ ]

byte[ ]

byte[ ]

byte[ ]

byte[ ]

byte[ ]

CPU

byte[ ]

byte[ ]

byte[ ]

byte[ ]

byte[ ]

byte[ ]

CPU

CPU

CPU

Nested RecursiveAction subclasses

/** An array of byte arrays to encrypt. */private byte[][] dataIn;/** The encrypted byte arrays. */private byte[][] dataOut;/** The secret key spec used to encrypt the arrays. */private SecretKeySpec secretKeySpec;

/** Encrypts the dataIn byte arrays in one pass. */public void encryptSinglePass() { for (int i = 0, count = dataIn.length; i < count; i++) { encryptArray(i); }}

/** Encrypts the byte array for the given index. */private void encryptArray(int index) { try { Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); dataOut[index] = cipher.doFinal(dataIn[index]); opLog.append(" -" + indexId); } catch (Exception e) { throw new RuntimeException(e); }}

Fork-Join Example – Single Pass EncryptionThe array of byte arrays dataIn was populated with data, and the SecretKeySpec required by AES was precalculated from a pass phrase.

The encryptSinglePass() method calls encryptArray() for each index – one at a time using 1 CPU.

The encryptArray() method performs the encryption on one single array. The entire encryption job can be divided into units that encrypt one array by calling this.

/** A RecursiveAction that executes an atomic task or divides it up. */public class ForkAction extends RecursiveAction { private int startIndex, endIndex;

/** Creates one of these, storing the partitioning indexes. */ public ForkAction(int startIndex, int endIndex) { this.startIndex = startIndex; this.endIndex = endIndex; }

/** Performs the computation - either breaks task up or executes. */ @Override public void compute() {

// If more than one array, break this task into two smaller ones if (startIndex < endIndex) { int mid = (startIndex + endIndex) / 2; ForkAction firstHalf = new ForkAction(startIndex, mid); ForkAction secondHalf = new ForkAction(mid + 1, endIndex); invokeAll(firstHalf, secondHalf); }

// If only one array, compute this task directly. else { encryptArray(startIndex); } }}

Fork-Join Example – ForkJoinTask Subclass

This RecursiveAction subclass stores a range of array indexes.

If this action is for more than one index, it will be divided into two actions that cover a smaller range (until range = 1).

If this action is small enough to execute directly (has only one array), encryptArray() (from the previous slide) is called.

The smaller actions are submitted (to the ForkJoinPool) when invokeAll() is called.

/** Encrypts the arrays by defining a ForkAction for all arrays. */public void encryptForkJoin() { // The default constructor assigns all available CPUs. ForkJoinPool pool = new ForkJoinPool(); // This instance encompasses the indexes of all the byte arrays. ForkAction forkAll = new ForkAction(0, dataIn.length - 1); // Submit the outermost task - its compute() will start splitting. pool.invoke(forkAll);}

Fork-Join Example – ForkJoinPool Creation

This method starts the execution and the splitting of the forkAll into smaller and smaller index ranges.

The processing will start with only one ForkJoinTask, a ForkAction that spans all byte arrays to encrypt.0-9

The example encrypts 10 arrays, so the first ForkAction is for 0-9.

1

0-4

0-2

2

0

0-1 3 4

3-4

5-9

5-7

75-6 8 9

8-9

65

/** A Callable that executes a single atomic encryption. */public class ForkCallable implements Callable<Object> { private int index; /** Creates one of these, storing the index. */ public ForkCallable(int index) { this.index = index; } /** Performs the computation - encrypts for a single array. */ @Override public Object call() { encryptArray(index); return null; }}

/** Encrypts the dataIn byte arrays by invoking all at once. */public void encryptExecutor() { ForkJoinPool pool = new ForkJoinPool(); List<ForkCallable> tasks = new ArrayList<>(); for (int i = 0, count = dataIn.length; i < count; i++) { tasks.add(new ForkCallable(i)); } pool.invokeAll(tasks);}

Fork-Join Example – Executor / Callable

This Callable subclass will encrypt a byte array for a single index.

The Callable implementation simply calls the established encryptArray() method for this instance’s assigned index.

ForkJoinPool also implements the ExecutorService interface, which has an invokeAll() that accepts a collection of Callable instances. Create and pass a list of ForkCallables, one per index, to the pool.

Fork-Join Example – Test Results

• Timing of three AES encryption examples:– Single: Single-threaded sequentially executed encryptions– Forked: Fork-Join RecursiveAction subclasses (split/invoked)– Executor: Submit Callable list, using pool as ExecutorService

• Timing trials in ms to encrypt 10 arrays of 60,000 bytes.

Single: 180.634; 13.207; 12.459; 12.774; 12.442; 12.553; 12.440; 12.628;

Forked: 9.220; 7.007; 8.478; 6.902; 7.593; 6.808; 8.810; 7.111;

Executor: 8.979; 6.851; 7.133; 6.827; 7.295; 7.894; 8.406; 6.873;

• Observations:– Both Forked and Executor were almost twice as fast (2 CPUs)

– Separate logging identified 2 concurrent threads of activities

– We had to write very little code to leverage parallel processing

– The target application MUST BE splittable into smaller activities

Fork-Join Example – Test Results

• Concurrency of three AES encryption examples:– Single: Single-threaded sequentially executed encryptions– Forked: Fork-Join RecursiveAction subclasses (split/invoked)– Executor: Submit Callable list, using pool as ExecutorService

• Concurrency for encrypting 10 arrays of 60,000 bytes.– The number is the index of the array being processed– The + means starting, and the – means ending.

Single: +0 -0 +1 -1 +2 -2 +3 -3 +4 -4 +5 -5 +6 -6 +7 -7 +8 -8 +9 -9

Forked: +0 +5 -0 +1 -5 +6 -1 +2 -2 +3 -6 +7 -3 +4 -7 +8 -4 +9 -8 -9

Executor: +0 +9 -0 +1 -9 +8 -1 +2 -8 +7 -7 +6 -2 +3 -6 +5 -3 +4 -5 -4

Support for Dynamic Languages – JSR-292

Copyright © 2011 – Oracle Corporation (lifted from an Oracle presentation)

Dynamic Languages on the JVM – Why?

• Dynamic languages provide flexibility/productivity– Sometimes at a cost: runtime errors - lack of strong typing

• Many dynamic languages have been created for the JVM– These languages can evolve faster than Java– They have filled gaps in functionality that Java isn’t filling now

• They can implement custom grammars– DSLS - Domain specific languages – For a particular purpose

– Reimplementation of an existing language on a robust platform

• The JVM provides a powerful runtime infrastructure– Robust execution environment

– Cross-platform

– Memory management and JIT optimization

– Security already implemented

– Huge, mature collection of libraries

JVM for Dynamic Languages – What’s Missing?

• Java is statically (compile-time) typed– Dynamic languages lack static typing information– Dynamic languages do not require declaration of variable types– Dynamic languages can call methods not declared in class/interface– Code of some languages dynamically changes at runtime– Byte-code verification limits what is acceptable without new commands– Runtime verification must be ennhanced for dynamic types

• Languages with multiple inheritance are hard to implement– The JVM support is limited to Java’s single inheritance

– Adding such support does not have to mess up Java’s strong typing

• But aren’t dynamic languages already running on the JVM?– SLOW: Reflection is often used for dynamic method discovery/calls– HARD: Entire meta-frameworks are being created – e.g., in Groovy– Currently, dynamic language providers are forced to code work-arounds

Instance Method in the JVM

public class C13_Acme { private LinkedHashMap<String, Integer> cache; public void addValue(String key, Integer value) { cache.put(key, value); }

Our class, Acme, declares cache as a LinkedHashMap, enabling us to call put()

The addValue() method calls put(), a method in HashMap, LinkedHashMap’s superclass.

Instance Method in the JVM

public class C13_Acme { private LinkedHashMap<String, Integer> cache; public void addValue(String key, Integer value) { cache.put(key, value); }

Javap extract for the cache.put(key, value) method call: public void addValue(java.lang.String, java.lang.Integer); stack=3, locals=3, args_size=3 0: aload_0 // stack[0] = this 1: getfield // stack[0] = cache 4: aload_1 // stack[1] = key 5: aload_2 // stack[2] = value 6: invokevirtual #22 // Methodref:java/util/LinkedHashMap.put: (Ljava/lang/Object;Ljava/lang/Object;) Ljava/lang/Object;Invokevirtual execution logic: The method caller is cache (stack[0]) Get class of the method caller (LinkedHashMap) Find method in target class (LinkedHashMap) It’s not there, look in superclass (HashMap) Create new frame: stack[0-2] => locals[0-2] In HashMap.put(): locals[0-2] = this, key, value

Our class, Acme, declares cache as a LinkedHashMap, enabling us to call put()

The addValue() method calls put(), a method in HashMap, LinkedHashMap’s superclass.

The byte code for an instance method call is invokevirtual, which is followed by a 2-byte methodref (entry #22 in the constant pool).

A methodref consists of the target object’s type, the method name, the parameter types (in parentheses) and return type.

The local variables for an instance method are “this”, then the passed params

JVM Dynamic Language Alternatives

• Currently-implemented method-invocation bytecodes:– invokevirtual, invokestatic, invokeinterface, invokespecial

– Method calls are tied to the variable’s type and validated at compile time.– At runtime, the instance class/superclasses are searched for the method.

• What alternatives exist now to compile of dynamic types?– Create a base type that has all the methods you’d want (bloated)

– Use reflection for unknown methods (slow and no field/method creation)

– Create meta classes and generate byte code (complex – but common)– ** Add a dynamic method invoker that resolves and validates at runtime

• Dynamic method invocation – JSR-292– New JVM byte code instruction: invokedynamic (first since Java 1.0)

– Allows declaration of untyped variables, unknown at compile time

– Deferral of dynamic variable type checking until runtime

– New linkage mechanism: method handles, not hard-coded descriptors– Not for use in Java, but includes support using new Java classes

JVM Dynamic Language Support

• MethodType – A specification of parameter and return types• Method Handle – A function pointer implemented in Java

– Method name, MethodType (params/return type), target type (the “this”)

– Calls methods: invoke(target, arg1…) => target.methodName(arg1…)

• MethodHandles – Utility class that adjusts/converts params– Provides lookup facilities for existing handles, creating as needed– Wrapper methods that convert param types, do pre/post processing

– Performs these lookups and transformations without using Reflection

• CallSite – Holds the method handle invokedynamic will call– Its method reference must name a “bootstrap” method with this

signature: CallSite methodName(Lookup caller, String name, MethodType type)

– This method, implemented by the class author, must return a CallSite– The JVM calls this method, passing the caller / name / type for that call– Then callSite.getTarget().invoke() is called with the stack params

Comparing Getter, Reflection, MethodHandle

/** Returns the result using getter on a casted target. */public Object getMethod(Object target, String methName) { return ((Person) target).getName(); }

/** Finds the method using reflection and invokes it. */public Object reflectMethod(Object target, String methName) { Method method = target.getClass().getMethod(methName, CLS_0); return method.invoke(target, OBJ_0); }

/** Invokes the given Method using reflection. */public Object reflectInvoke(Object target, Method method) { return method.invoke(target, OBJ_0); }

/** Finds the method using lookup and invokes it. */public Object handleMethod(Object target, String methName) { MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodType type = MethodType.methodType(String.class); MethodHandle handle = lookup.findVirtual(target.getClass(), methName, type); return (String) handle.invoke(target); }

/** Invokes the given MethodHandle. */public Object handleInvoke(Object target, MethodHandle handle) { return (String) handle.invoke(target); }

Comparing Getter, Reflection, MethodHandle

assignTarget: 0.866 nsgetMethod: 1.151 nsreflectMethod: 1,158.387 nsreflectInvoke: 80.720 nshandleMethod: 9,345.009 nshandleInvoke: 3,864.379 ns assignTarget: 0.866 nsgetMethod: 1.352 nsreflectMethod: 1,123.120 nsreflectInvoke: 95.068 nshandleMethod: 9,120.293 nshandleInvoke: 3,992.703 ns assignTarget: 0.866 nsgetMethod: 1.106 nsreflectMethod: 1,142.782 nsreflectInvoke: 91.995 nshandleMethod: 9,418.275 nshandleInvoke: 3,898.082 ns

Additional Enhancements for SE 7

• Swing Enhancements– Nimbus look and feel – Example: Eclipse 4.2– Shaped and translucent windows– Jlayer: Transparent decorator, catches client component events– Improved 2D rendering performance (X-windows)

• Libraries and Core Classes– Sockets Direct Protocol: Lightning-fast networking (Fiber)

– Security: Elliptic curve cryptography; TLS 1.2; Stronger algorithms

– JAXP 1.4.4

– JAX-WS 2.2

– JAXB 2.2

– JDBC 4.1: RowSetFactory, FilteredRowSet, CachedRowSet

Additional Enhancements for SE 7

• G1 “Garbage first” Garbage Collector – Regional garbage collections (less pauses for large heaps)– Predictable and configurable GC pauses – -XX:+UseG1GC ; -XX:MaxGCPauseMillis ; -XX:GCPauseIntervalMillis

• Heap and Memory Management– Compressed 64-bit object pointers: 4-byte heap addresses – Elimination of synchronization for localized objects (e.g., StringBuffer)– Elimination of defensive copying if target unchanged– Allocation of method-local objects on the stack instead of the heap

• Core Classes and Tools– Upgrade classloader architecture

– Locale and extensible currency enhancements

– Javadoc support for stylesheets

Coming in Java SE 8

• Modular Programming – JSR-294– Language and VM Support– Platform modularization – Deploy only what you need

• Project Lambda – JSR-335– Lambda expressions (closures, anonymous methods, function pointers)

– Virtual extension methods, default methods

– Method references– Bulk data operations

• More Enhancements– Annotations on Java types – JSR-308

– Continuations: suspend and resume thread execution

– Tail calls and tail recursion (functional programming support)

– Default method

• JVM Convergence: HotRockit = (HotSpot + JRockit)

Resources

• Next steps – Download– Java 7: http://www.oracle.com/technetwork/java/javase/downloads

– Eclipse 4.2: http://www.eclipse.org/downloads/index-developer.php

• References:– API: http://download.oracle.com/javase/7/docs/api

– Features: www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html

– Java spec: http://download.oracle.com/javase/7/specs/jls/JLS-JavaSE7.pdf

– JVM spec: http://download.oracle.com/javase/7/specs/jvms/JVMS-JavaSE7.pdf

– http://download.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html

Thank you all for your kind attention !!