Java 8’s Functional Fomentation
Java 8 has revolutionized Java. It’s easily the most significant release of Java in the last 10 years. There are a ton of new features including default methods, method and constructor references, and lambdas, just to name a few.
One of the more interesting features is the new java.util.stream
API, which as the Javadoc states, enables
functional-style operations on streams of elements, such as map-reduce transformations on collections
Combine this new API with lambda expressions and you end up with a terse, yet, powerful syntax that significantly simplifies code through the application of projections.
Take, for example, the ostensibly simple task of filtering a collection. In this case, a simple Collection
of Message
types, created like so:
Creating a Collection of Messages
List<Message> messages = new ArrayList<>(); messages.add(new Message("aglover", "foo", 56854)); messages.add(new Message("aglover", "foo", 85)); messages.add(new Message("aglover", "bar", 9999)); messages.add(new Message("rsmith", "foo", 4564));
With this collection, I’d like to filter out Message
s with a delay
(3rd constructor parameter) greater than 3,000 seconds.
Previous to Java 8, you could hand jam this sort of logic like so:
Filtering old school style
for (Message message : messages) { if (message.delay > 3000) { System.out.println(message); } }
In Java 8, however, this job becomes a lot more concise. Collections now support the stream
method, which converts the underlying data structure into a iterate-able steam of objects and thereby permits a new breed of functional operations that leverage lambda expressions. Most of these operations can be chained as well. These chain-able methods are dubbed intermediate, methods that cannot be chained are denoted as terminal.
Briefly, lambda expressions are a lot like anonymous classes except with a lot less syntax. For example, if you look at the Javadocs for the parameter to a Stream
’s filter
method, you’ll see that it takes a Predicate
type. Yet, you don’t have to implement this interface as you would, say, before Java 8 with an anonymous class. Consequently, the Predicate
lambda expression for filtering all values of delay
greater than 3000 would be:
Lambda expression
x -> x.delay > 3000
Where x
is the parameter passed in for each value in the stream and everything to the right of the ->
being the expression evaluated.
Putting this all together in Java 8 yields:
Streaming lambdas!
messages.stream().filter(m -> m.delay > 3000).forEach(item -> System.out.println(item));
Interestingly, due to some other new features of Java 8, the forEach
’s lambda can be simplified further to:
Streaming lambdas are even shorter!
messages.stream().filter(m -> m.delay > 3000).forEach(System.out::println);
Because the parameter of the forEach
lambda is simply consumed by the println
, Java 8 now permits you to drop the parameter entirely.
Earlier, I mentioned that streams permit you to chain lambdas – in the case above, the filter
method is an intermediate method, while the forEach
is a terminal method. Other intermediate methods, that are immediately recognizable to functional programmers, are: map
, flatMap
, and reduce
, to name a few.
To elaborate, I’d like to find all Message
s that are delayed more than 3,000 seconds and sum up the total delay time. Without functional magic, I could write:
Prosaic Java
long totalWaitTime = 0; for (Message message : messages) { if (message.delay > 3000) { totalWaitTime += message.delay; } }
Nevertheless, with Java 8 and a bit of functional-foo, you can achieve a more elegant code construct like so:
Java 8 elegance
long totWaitTime = messages.stream().filter(m -> m.delay > 3000).mapToLong(m -> m.delay).sum();
Note how I am able to chain the filter
and mapToLong
methods, along with a terminal sum
. Incidentally, the sum
method requires a specific map style method that yields a collection of primitive types, such as mapToLong
, mapToInt
, etc.
Functional style programming as a core language feature is an astoundingly powerful construct. And while a lot of these techniques have been available in various 3rd party libraries like Guava and JVM languages like Scala and Groovy, having these features core to the language will surely reach a wider audience of developers and have the biggest impact to the developmental landscape.
Java 8, without a doubt, drastically changes the Java language for the better.
Reference: | Java 8’s Functional Fomentation from our JCG partner Andrew Glover at the The Disco Blog blog. |
I understand Java 8 has launched new features, but hey who requires these complicate features
I dont think anybody will use them