6 min read

java8 This article highlights the top momentum builders for the adoption of the Java 8 platform within enterprises. Most enterprises have invested heavily in a portfolio of Java applications. In order to enhance the functionality and capabilities of that portfolio, enterprises are constantly looking to upgrade API versions or bring in newer frameworks to enhance the applications. In no order of priority, I have picked 5 things that appealed to me. There are several exciting features that were launched as part of Java SE 8 and several exciting additions that will be a part of Java SE 9. In this article we explore only the additions that are already part of the current release, Java SE 8. In a subsequent post, I will cover exciting enhancements that will be released as a part of Java SE 9.

I talk to several enterprises every month. This article leans towards the benefits of adopting JDK 8 for large enterprises. Since these large companies have made significant investments in the Java platform and have built a portfolio of Java applications, we will discuss briefly the features that will benefit current applications in the long run.

HashMap Enhancement for Improved Application Performance

JDK 8 has introduced an improved strategy to deal HashMaps that have a high collision rate. A poor hash function that always returns the same bucket can effectively turn a HashMap into a linked list. Performance degrades to O(n) instead of O(1). Hash bins containing a large number of colliding keys improve performance by storing their entries in a balanced tree instead of a linked list. This ensures performance of order O(log(n)) even in worst case scenarios where the hash function is not distributing keys properly. While this is an internal detail, simply upgrading to JDK 8 from older JDK versions will allow certain applications to see performance improvements if they use HashMaps heavily and have a large amount of entries in the HashMaps.

You can read more about the performance improvements observed in JDK 8 in performing put and get operations in hashmap table here

Lambda Expressions for Supporting Functional Programming Constructs

A lambda expression is like a method, it provides a list of formal parameters and a body, which can be an expression or a block of code, expressed in terms of those parameters.

The basic syntax of a lambda is:

either
(parameters) -> expression
or
(parameters) -> { statements; }

A lambda expression provides a way to represent a one-method interface using an expression. A lambda expression is a block of code that you can pass around so it can be executed later, just once or multiple times.

Below are three examples of typical scenarios in Java that can now be replaced by Lambda expressions

  1. In Swing GUI programming, when a button is clicked, a callback action is invoked. The callback action is typically implemented in an anonymous listener class or by constructing an instance of a class that implements the listener interface.
  2. When work needs to be executed in a separate thread, that work can be put into the run method of an anonymous Runnable class or a class implementing the Runnable interface and providing a concrete implementation of the run() method can be instantiated and passed to a Thread object.
  3. In the Collections API, a Comparator object is passed, for example, to a sort() method. The Comparator interface is implemented in an anonymous class typically.

Such interfaces depicted in the above examples are called Functional Interfaces. A Functional Interface is an interface with just one abstract method declared in it. A lambda expression can be provided whenever an object of such a functional interface with a single abstract method is expected. A Lambda expression is thus a method without a true declaration. There is no need for a name, return value, or access modifier.

There is a subtle difference between an anonymous class and Lambda expression, which is the use of ‘this’ keyword. For a lambda expression ‘this’ keyword resolves to the enclosing class where the lambda expression is written. For an anonymous class ‘this’ keyword resolves to anonymous class. Another difference between a lambda expression and anonymous class is in the way these two are compiled. The Java compiler compiles a lambda expression and converts it into a private method of the class. It uses the invokedynamic instruction that was added in Java 7 to bind this method dynamically.

We explore Lambda expressions and the functional programming style in a more detailed article in the future.

New Date and Time API for Ease of Use

The Date-Time APIs, introduced in JDK 8 alleviate some of the issues that developers faced with the previous Date-Time API.For example, the existing classes (such as java.util.Date and SimpleDateFormatter) aren’t thread-safe, leading to potential concurrency issues for users. Some of the date and time classes also exhibit quite poor API design. For example, years in java.util.Date start at 1900, months start at 1, and days start at 0.

The new API avoids some issues by ensuring that all its core classes are immutable and represent well-defined values. The new API allows supports different calendaring systems used in other areas of the world, such as Japan or Thailand, that don’t necessarily follow ISO-8601.

The new API also provides LocalDate and LocalTime. They are local in the sense that they represent date and time from the context of the observer, such as a local calendar or your clock. There is also a composite class called LocalDateTime, which is a pairing of LocalDate and LocalTime.

The new Time API prefers enums over integer constants for months and days of the week. One useful class is DateTimeFormatter for converting datetime objects to strings.

Bulk Data Operations for Collections

The Java platform made a huge leap in Java 8 by enhancing the Collections framework and related APIs. Functionality was added to perform bulk operations on data. The bulk data operations include both serial (on the calling thread) and parallel (using many threads) versions of the operations. Lambda expressions are generally used to express these operations. These automatically parallelizable bulk data operations are also commonly referred to as "filter/map/reduce”.

The java.util.stream API has been added to Java 8. The Collection interface has been extended with stream() and parallelStream() default methods to get the Stream for sequential and parallel execution.

The serial implementation helps bridge operations on existing collections to parallel operations that do not change the threading model of the application.

The parallel implementation provides the opportunity to accelerate operations upon large amounts of data by dividing the task between multiple threads (processors). This builds upon the java.util.concurrency Fork / Join features introduced in Java 7.

For both the serial and parallel implementations an "eager" mode and a "lazy" mode are possible. In eager mode operations upon data are performed directly upon the data at the time the operation function is invoked. In lazy mode the operations upon the data are deferred until the final result is requested. Lazy mode operation allows the implementation more optimization opportunities based upon reorganization of the data and operations to be performed.

Nashorn Engine for Javascript Interoperability and Performance

The JavaScript engine in Java 7 was replaced by another JavaScript engine in Java 8 called Nashorn. This is a lightweight high-performance JavaScript runtime that can be used stand-alone through the jus command-line tool and also as an embedded scripting engine inside Java applications. Java types can be implemented and extended from JavaScript making Java and JavaScript interoperable and the integration seamless. The Nashorn engine is based on JSR 292 and uses the invokedynamic keyword that was added to Java 7.

Until Java 7, the JavaScript engine was based on Mozilla Rhino. Nashorn is a play on Rhino and means rhinoceros in German. By making use of Nashorn, a software developer can embed JavaScript in a Java application and also invoke Java methods and classes from JavaScript code.

While the discussion above highlights five exciting new additions to the Java platform, there are several more as part of Java 8 that will be highlighted in future articles. Manually analyzing large code bases and making changes to code, testing, and deploying the code base is both time-consuming and fraught with risks. Nagarro has an automated solution to analyze code bases and identify the specific points in the code where changes need to be made. Large portions of the migration can also be automated. If you are considering migrating to Java 8, please visit our solution page for Java Modernization at http://www.nagarro.com/java-modernization to learn about a simple, accelerated and cost effective way to migrate to JDK 8.