Java 8's functional fomentation

Functional-foo has come to Java at last

Java 8 has revolutionized Java. It’s easily the most significant release of Java in the last 10 years. It includes 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 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:

1 List<Message> messages = new ArrayList<>();
2 messages.add(new Message("aglover", "foo", 56854));
3 messages.add(new Message("aglover", "foo", 85));
4 messages.add(new Message("aglover", "bar", 9999));
5 messages.add(new Message("rsmith", "foo", 4564));

With this collection, I’d like to filter out Messages with a delay (third constructor parameter) greater than 3,000 seconds.

Previous to Java 8, you could hand-jam this sort of logic like so:

1 for (Message message : messages) {
2   if (message.delay > 3000) {
3     System.out.println(message);
4   }
5 }

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:

1 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:

1 -> 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:

1 -> 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 Messages that are delayed more than 3,000 seconds and sum up the total delay time. Without functional magic, I could write:

1 long totalWaitTime = 0;
2 for (Message message : messages) {
3   if (message.delay > 3000) {
4     totalWaitTime += message.delay;
5   }
6 }

Nevertheless, with Java 8 and a bit of functional-foo, you can achieve a more elegant code construct like so:

1 long totWaitTime = -> 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 third-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.

This story, "Java 8's functional fomentation" was originally published by The Disco Blog.