A couple of months ago, Oracle released JDK 8, representing a step towards functional programming. We’ve recently started to use Java 8 for one of our projects and I thought I should share a bit from this experience.
Firstly, you may have noticed that there are some similarities between Java 8 and Guava. As we extensively use Guava in our projects, we started by replacing its classes with the ones from java.util.
Optional is a way of wrapping a null value-it is similar to Haskell’s Maybe and Scala’s Option. The main difference is that Guava’s Optional lacks some of the methods for dealing with absent values and the functional-style methods.
In this example,
Optional.ofNullable() creates a reference that may or may not be null (the alternatives are to create an
Optional.of() to wrap a non-null value or
We could shorten this code by using lambda expressions. Printing the value of the Optional is now done using Method Reference. Instead of having all these checks, we can filter the value (and return a new Optional) and then use a Consumer(print in this case) only if that value is present.
Guava’s Joiner was one of the solutions for joining multiple strings, but the standard API has now introduced
String.join(). The Stream API also comes with a joining Collector, but more on this later.
Probably the most important fact about Java 8 is that it comes with some of the features of functional languages. It allows functions to be passed as arguments or returned by methods hence having operations expressed succinctly with lambdas.
Say you have a single-method class. This usually happens when you’re trying to pass functionality to another method. Lambdas give the possibility of expressing this more compactly. Or you could have @FunctionalInterface and then use it in lambda expressions.
Method references or lambdas for calling an existing method. There are four types of method references:
- To a static method
- To an instance method
- To an instance method of an arbitrary object
- To a constructor
The next example shows the different ways of iterating over expressions, from the simple for-loop, to using lambdas or method references. While the code is more concise, the most important aspect of
forEach is that it can be made parallel.
The Stream interface is similar to the Iterator. Streams do not store elements, but send values from a source through a pipeline of operations, somehow similar to lazily constructed Collections. The interface supports parallel execution: convert Collections to Stream, then process in parallel and then join the resulting elements in a Collection. Streams are faster and more memory efficient than Lists and also support some of the functional-like methods: map, filter, reduce, that Lists lack. You could turn a stream into a List by calling
The new Java Date and Time API represents a massive improvement compared to the previous APIs (mutable objects and poorly named methods). Java 8 comes with a new thread-safe Date Time API, which in similar to Joda. The
java.time package provides
LocalDateTime that models date and time values in ISO-8601 calendar system. It also provides classes for working with time zones
ZonedDateTimeand has a formatting/parsing API.
This was a very short introduction on what you can currently do in Java 8. Have you started using it or do you plan on switching to it soon? We’d like to hear your opinions so do leave us a comment below or send us a tweet!