ABIS Infor - 2016-06

Java SE 8 new features

Gie Indesteege (ABIS) - June 1st 2016

Abstract

After almost 20 years of Java presence in the IT world, and several new features added in subsequent versions, Java SE 8 presents a new milestone in the Java history. Although this version 8 was released already 2 years ago, a lot of current Java developers still await a good business case to upgrade, or a clear explanation of the new features like lambda expressions and streams.

From procedural to functional programming

One of the most awaited features, named lambda expressions, which allows for functional programming, is now included in Java. Key concept is that functionality can be passed as data, and code becomes more concise (ref. 2).

As an example, you want to implement your own print functionality, framing the object contents in asterisks:

e.g. a person's first and last name - James Bond - should be printed as: *** James Bond ***

  • Option 1: code a System.out.println( ) statement at any place where you want to use this function
	System.out.println("*** " + firstName + " " lastName + " ***");
  • Option 2: create your own method which implements this function, and invoke it where appropriate
	void printInfo(Person p) {
		System.out.println("*** " + p.toString() + " ***");
	}

supposed the toString() method is implemented in the Person class

	printInfo(this);
  • Option 3: create a (functional) interface which can be used at any place via a lambda expression
	interface MyPrint {
		void printInfo();
	}

assign lambda to an interface reference

	MyPrint mp = (p) -> System.out.println("*** " + p.toString() + " ***");

and use that reference when necessary

	mp.printInfo(person1);

Note that, in the last option, an instance of a class implementing the functional interface is automatically created.

Using lambda expressions makes your code more flexible, especially with more complex logic. Suppose you want only print that info for persons, whose last name starts with 'B'. This can be easily accomplished via the following lambda:

	mp = p -> System.out.println( p.getLastName().startsWith("B") ?
				 "*** " + p.toString() + " ***" : "");

Lambda expressions rely a lot on functional interfaces, a number of them predefined in the new java.util.function package. Examples include Predicate, Consumer, Supplier, Function and BinaryOperator.

Iterating streams instead of collections

The mentioned functions are very useful in the handling of collections, who are no longer to be iterated externally, but can be accessed more efficiently via internal iterators. This is made possible via the new Stream interface, which makes extensive use of the lambda facilities.

Suppose you have a list of persons:

	List<Person> personList = ...

and want to print relevant info in the format used above. The following code could be used:

	personList.stream().filter(p -> p.getName().startsWith("B"))
			.forEach(p -> mp.printInfo(p));

or with a method reference notation (which is a short hand notation for lambda's)

	personList.stream().filter(p -> p.getName().startsWith("B"))
			.forEach(mp::printInfo);

Streams represent a sequence of elements on which one or multiple operations can be performed, typically based on a "map and reduce" technique. Java 8 keeps the processing optimisation for the iteration of the stream internally, so you can concentrate on the functionality.

An example to find the eldest person from the list of persons:

	personList.stream()
		.reduce((p1,p2) -> p1.age > p2.age ? p1 : p2)  // checking age
		.ifPresent(p -> p.printInfo());

Note, the last line is based on the new Optional container concept, whose value may be null or non-null.

Another important feature of streams is the possibility to handle the elements in parallel, which opens the door for multicore execution of applications. Just replace Stream by ParallelStream, and you're done.

New APIs

But Java SE 8 offers other new possibilities: easier date/time API, default methods in interfaces, improvements in String handling, ... to just name a few.

A default method (also known as extension method) in an interface, as the name implies, acts as a predefined method for an implementing class, if it is not explicitly defined in there.

For example:

	interface MyConverter<F, T> {
		T convert(F from);
		default void sayHello(String s) {
			System.out.println("Hello myConverter " + s);
		}
	}
	class MyConv implements MyConverter<Integer, String> {
		String convert(Integer i) { return i.toString(); }
	}

is used in the main() of an application as

	MyConv mc = new MyConv();
	String s = mc.convert(5);
	mc.sayHello(s);

The brand new date and time API of Java 8 is comparable with the JODA library (ref. 3). Localised date and time information, and utility functions for calculating date and time differences are now easy to accomplish, as well as formatting and parsing of these dates and times.

	DateTimeFormatter frenchFormatter = 
    	  DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.FRENCH);
	LocalDate labourDay = LocalDate.parse("01 mai 2016", frenchFormatter);
	System.out.println(labourDay);

You know the problem of joining Strings with:

	System.out.println("*** " + firstName + " " + lastName + " " + email + " ***";

Perhaps a better solution is:

	StringJoiner sj = new StringJoiner(" ","*** ", " ***");
	sj.add(firstName).add(lastName).add(emailAddress);
	System.out.println(sj);

or simplified.

	System.out.println(String.join(" ", firstName, lastName, emailAddress);

Improved performance, security, concurrency, ...

Less visible, but also important are improvements in the JVM for concurrency, parallelism, garbage collection, ... to enhance the performance and synchronisation, especially for parallel execution on multi core platforms.

Not to forget, the more and better security, which helps to create reliable applications for all users.

Another important aspect of Java SE 8 is the enablement of JavaScript functions via the Nashorn engine, embedded in the JVM.

Conclusion

This article gives you already a first overview of the new way of programming future proof applications, based on Java SE 8. This will enable programmers to express their code more clearly and concisely, with less boilerplate.

For better modularity in Java applications, we still have to wait for the Java SE 9 implementation of the Jigsaw project.

References

  1. What's new in JDK 8: http://www.oracle.com/technetwork/java/javase/8-whats-new-2157071.html
  2. Why lambda? http://www.lambdafaq.org/why-are-lambda-expressions-being-added-to-java/
  3. Joda-time library http://www.joda.org/joda-time/