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.

Notice to our Readers
We're now using social media to take your comments and feedback. Learn more about this here.