Mark Addison bio photo

Mark Addison

Software Engineer from Surrey England

Email Twitter Google+ LinkedIn Github Stackoverflow

Overview

1. Lambda Expressions (aka Closures or by some anonymous functions)

The long awaited feature of lambda expressions were added to Java 8 to provide a concise way to represent one methods interface using an expression. The main goal of lambda expressions is to allow developers to build better libraries, bulk operations which can run on collections - and facilitate the move from sequential to parallel operations. In Java 8, a lambda expression consists of a comma separated list of the formal parameters enclosed in parentheses, an arrow token (->), and a body. The data types of the parameters can always be omitted, as can the parentheses if there is only one parameter. The body can consist of a single statement or a statement block. It is suggested that they should be used where previously anonymous inner classes were used to both simplify the code and improve expressiveness of the language.

Readers interested in a more in-depth description of this feature are referred to Java SE 8: Lambda Quick Start

2. Parallel Operations

3. New Date/Time APIs

One of the major bugbears of Java developers has been the inadequate support for the date and time use cases for ordinary developers. The pre-existing API for date/time classes were not very intuitive. For example, in java.util.Date years start at 1900, months start at 1, and days start at 0; and on top of that the classes were not thread-safe.

With the advent of Java 8 there is a new time package java.time (JSR-310), the key concepts are:

  • Immutability: the core classes of the new API are immutable and represent well-defined values, removing the burden from developers to consider issues around concurrency and thread-safety.
  • Separation of chronologies: allowing different calendar schemes to be utilised in some areas of the world, such as Japan or Thailand, that don’t necessarily follow ISO-8601.

The new time classes provides nanosecond time resolution, which is fantastic news for developer who complained that the millisecond resolution limitation in Joda-Time was insufficient for database timestamps.

For many years developers have painstakingly been working around many of the inadequacies of the standard Java Date/Time classes, for example calendars and no support for Coordinated Universal Time (UTC). In many cases adopting and using the excellent Joda-Time classes, indeed many of the concepts implemented in Joda-Time have influenced the design of the new Date/Time classes in Java 8. That is not to say that the Joda-Time classes were perfect, in fact one of their limitations was the resolution of time to only milliseconds.

3.1. Key Features

Time-Zone Database (TZDB) that provides information about every time zone change globally since 1970.

All the core classes are constructed using factory methods. For example, when constructing a value by its constituent fields the factory method of should be called. There are factory methods to and from, which support the conversion of one core class to another depending upon the context of the conversion operation required. There are also parse methods which take in strings. Here are some examples:

LocalTime localTime = LocalTime.now();
System.out.println("Local time now: " + localTime);

LocalTime newTime = localTime.plusMinutes(90);
System.out.println("Local time +90 minutes: " + newTime);

LocalDate today = LocalDate.now();
System.out.println("Today: " + today);

LocalDate yesterday = today.minusDays(1);
System.out.println("Yesterday: " + yesterday);

LocalDateTime localDateTime = yesterday.atTime(8, 0);
System.out.println("Yesterday at 8 a.m: " + localDateTime);

LocalDateTime earlyMorning = LocalDate.of(2015, Month.FEBRUARY, 1).atStartOfDay();
System.out.println("The start of today: " + earlyMorning);

Local time now: 17:07:59.864
Local time +90 minutes: 18:27:59.864
Today: 2015-02-01
Yesterday: 2015-01-31
Yesterday at 8 a.m.: 2015-01-31T08:00
The start of today: 2015-02-01T00:00

4. Concurrent Accumulators and Adders

The java.util.concurrent.atomic package has been extended with classes that allow for concurrent, scalable, and updatable variables. LongAccumulator and LongAdder have been introduced to handle Long numbers; and the corresponding classes DoubleAccumulator and DoubleAdder have been introduced to support tasks requiring Doubles. These can be utilised in cases where it is necessary to sum a value across multiple threads. The usual contention is ameliorated by permitting each thread to essentially work as if these are independent variable.

As a simple test I have implemented a benchmark application which compares the execution of LongAdder versus AtomicLong versus primitive long (with No-Op added as a ‘baseline’). Code for this example is available on Git Hub BenchmarkLongAdder.java

The benchmark duration results when run for a range of number of threads from between 1 and 50, on a hyper-threaded 12 core machine, are present in an excel spreadsheet, with a graph BenchmarkLongAdder.xlsx

A graph has been included which depicts the relative performance of each type of ‘thread’ when summing values using each type of concurrency strategy. Note, the new LongAdder is almost linear in terms of performance, when considered against a No-Op, and a significant improvement in comparison to the atomic class AtomicLong

5. Nashorn (JavaScript Engine)

Nashorn is a completely new JVM supported JavaScript engine, providing in-process interoperability between Java and JavaScript code directly at execution. In reality, Nashorn is an interpreter embedded in Java applications which allows for seamless integration between Javascript and Java.

To exemplify, and for simplicity sake, consider a simple requirement, summing together two numbers.

5.1. Making Calls to Java from Javascript

In Java this could be achieved by defining and interface and a corresponding class which implements the functionality, which can be called from Javascript as follows:

public interface Adder {
  int sum(int a, int b);
} 

public class AdderImpl implements Adder {
   int sum(int a, int b) { return a + b }
}

ScriptEngineManager engineManager = new ScriptEngineManager();
ScriptEngine engine = engineManager.getEngineByName("nashorn");
Invocable invocable = (Invocable) engine;
Adder adder = invocable.getInterface(AdderImpl.class);
System.out.println(adder.sum(2, 3));

5.2. Making Calls to Javascript from Java

Consider defining a Javascript function sum which when called produces the sum of two numbers. This can be called from Java using the Nashorn engine:

package example.nashorn;

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

public class Sum {
   public static void main(String args) throws Throwable {
      ScriptEngineManager engineManager = new ScriptEngineManager();
      ScriptEngine engine = engineManager.getEngineByName("nashorn");
      engine.eval("function sum(a, b) { return a + b; }");
      System.out.println(engine.eval("sum(1, 2);"));
   }
}

This is just a flavour of the support provided by Nashorn, for a more detailed description of other features I refer you to an OTN Article Oracle Nashorn

6. HotSpot Improved

One significant change to be aware of is the removal of permanent generation from the Hotspot JVM and thus elimination of the onerous task of monitoring and tuning the size of the permanent generation space. The consequences of the PermGen removal is that PermSize and MaxPermSize JVM arguments are superfluous and if present will be ignored, with a warning issued; you will never receive a java.lang.OutOfMemoryError: PermGen error again (hurrah). This has been replaced with a new scheme Metaspace which is allocated out of native memory. At runtime, the allocation of the Metaspace will be dynamically re-sized to meet each application’s need. Obviously, the limitation is the amount of native memory available. Note a new error will result when memory becomes exhausted java.lang.OutOfMemoryError: Metaspace. As a consequence developers should monitor the native heap space size used during application execution.

7. JDEPS (Class Dependency Analyser)

jdeps is a command line tool that shows the package-level or class-level dependencies of Java class files.

As an example, here’s the output from analysing the Spring Framework Core lirary, spring-core-3.0.6.RELEASE.jar

spring-core-3.0.6.RELEASE.jar -> C:\Program Files\Java\jdk1.8.0_31\jre\lib\rt.jar
   org.springframework.core (spring-core-3.0.6.RELEASE.jar)
      -> java.io                                            
      -> java.lang                                          
      -> java.lang.annotation                               
      -> java.lang.ref                                      
      -> java.lang.reflect                                  
      -> java.util                                          
      -> java.util.concurrent                               
      -> org.apache.commons.logging                         not found
      -> org.springframework.asm                            not found
      -> org.springframework.asm.commons                    not found
   org.springframework.core.annotation (spring-core-3.0.6.RELEASE.jar)
      -> java.lang                                          
      -> java.lang.annotation                               
      -> java.lang.reflect                                  
      -> java.util
...
   org.springframework.util.xml (spring-core-3.0.6.RELEASE.jar)
      -> java.io                                            
      -> java.lang                                          
      -> java.util                                          
      -> javax.xml.namespace                                
      -> javax.xml.stream                                   
      -> javax.xml.stream.events                            
      -> javax.xml.stream.util                              
      -> javax.xml.transform                                
      -> javax.xml.transform.sax                            
      -> javax.xml.transform.stax                           
      -> org.apache.commons.logging                         not found
      -> org.w3c.dom                                        
      -> org.xml.sax                                        
      -> org.xml.sax.ext                                    
      -> org.xml.sax.helpers

8. Considerations

Java 8 has a significant number of new features which provide compelling reasons to adopt Java 8. However, as usual, any existing application being upgraded will require a considerable amount of testing and profiling to determine whether, for example, changes from Perm Gen to Metaspace positively affect performance; and whether this effort is justifiable. For greenfield application development I believe improvements in the performance of streams, HashMap, and concurrency classes will provide quantifiable benefits.

With the new date-time classes developers will need to assess whether any workarounds have been implemented in code being slated to run using Java 8. Consideration will be necessary as to what code modification may be required with respect to the new date-time API.