This article was originally posted by Johan Noren at MacGyver Development.
After more toying with Scala on my spare time while hacking Java in office hours I miss out on using all these functional idioms in my Java programs. So with Java 8 coming closer I got interested in how the JDK team is planning on utilizing the new Java closure syntax in for example the collections libraries to support a more functional style of programming. While I have it fresh in memory, let me tell you some cool aspects of this!
Closures in Java
[code language="java"]public interface ActionListener {
void actionPerformed(ActionEvent e);
}[/code]
So in JDK 7 or earlier syntax, this is how you would declare for example an ActionListener
[code language="java"]ActionListener l = new ActionListener() {
public void actionPerformed(ActionEvent e) {
doWork(e.getModifiers());
}
};[/code]
[code language="java"]ActionListener l = (ActionEvent e) -> doWork(e.getModifiers());[/code]
So you get rid of all the unnecessary boilerplate code inherent in anonymous class creations so common in Java. More pleasing examples of usages of this syntax
[code language="java"]Comparator c = (s1, s2) -> s1.compareToIgnoreCase(s2);[/code]
[code language="java"]FileFilter java = f -> f.getName().endsWith(".java");[/code]
There's a lot of interesting things going on here like how lexical scopes work, variable binding, type inference etcetera. Check out project lead Brian Goetz report on how these things work.
Java Collection libraries
So how will this be used in the collection libraries which are probably the most used toolkit of the Java platform? First of all, the Collections team has decided not to restart by rewriting the collections libraries from scratch. While mentioning that this might be a candidate for future JDK versions, version 8 will instead provide an evolutionary step forward in the Collections by adding extension methods to existing interfaces (List, Set, Iterable) and retrofit existing classes with new interfaces such as Stream.
A major shift will be from the imperative style of external iteration to the more functional style of internal iteration. For example, the recommended idiom in Java 5+ to change a property on all objects in a collection uses
[code language="java"]for (Car c : cars) {
c.setState(MOVING);
}[/code]
With closures you'll write this as
[code language="java"]cars.forEach(c -> { c.setState(MOVING); });[/code]
What are the benefits of this idiom? You move the control flow to the library instead of the client code. In this way the library can decide on potentially use laziness, parallelism and out-of-order execution to improve performance which will be showed in later examples.
You can pipeline operations. In this example the filter operation uses a predicate to decide which objects in the collection to pipe to the final forEach clause.
[code language="java"]cars.filter(c -> c.getWeight() > 2000)
.forEach(c -> { c.setState(STOPPED); });[/code]
And to store results from computations using for example the map operation which operates on each value in the piped collection use something like
[code language="java"]Set smallEngines = cars.filter(c -> c.getMaxSpeed() < 100) .map(c -> c.getEngine())
.into(new HashSet<>());[/code]
or to sum them. This is the well known functional idiom of map reduce.
[code language="java"]int sum = cars.filter(c -> c.getState() == MOVING)
.map(c -> c.getWeight())
.sum();[/code]
So, all these operations will not create temporary new collections and pass on to the next operation. Instead they operate lazily and stream values between the control blocks. This implies good performance when for example searching for the first object that satisfies some condition. The upstream iterator in this example will not continue the iteration when getFirst() has foun a match.
[code language="java"]Car fastCar = cars.filter(c -> c.getSpeed() > 120).getFirst();[/code]
When used to these constructs, a lot of boilerplate code should be possible to remove. Here Brian Goetz shows an example of a method in java.lang.Class as today
[code language="java"]for (Method m : enclosingInfo.getEnclosingClass().getDeclaredMethods()) {
if (m.getName().equals(enclosingInfo.getName()) ) {
Class<?>[] candidateParamClasses = m.getParameterTypes();
if (candidateParamClasses.length == parameterClasses.length) {
boolean matches = true;
for(int i = 0; i < candidateParamClasses.length; i++) {
if (!candidateParamClasses[i].equals(parameterClasses[i])) {
matches = false;
break;
}
}
if (matches) { // finally, check return type
if (m.getReturnType().equals(returnType) )
return m;
}
}
}
}
throw new InternalError("Enclosing method not found");[/code]
and how it could be rewritten without all the temporary variables making it both more readable and less error prone.
[code language="java"]Method matching =
Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.getFirst();
if (matching == null)
throw new InternalError("Enclosing method not found");
return matching;[/code]
There's a lot of more cool features on the project site, but before ending you should see how easy parallel computation can become. By streaming the pipeline via parallel() the library will try to divide the pipeline stream of operations to all your cores.
[code language="java"]int sum = cars.parallel()
.filter(c -> c.getState() == MOVING)
.map(c -> c.getWeight())
.sum();[/code]
Via the new interface Splittable you can also very easily use the Fork/Join framework for divide and conquer tasks.
Timeplans
2012/7 Expert Group formation
2012/9 Early Draft Review
2013/1 Public Review
2013/6 Proposed Final Draft
2013/8 Final Release
http://openjdk.java.net/projects/jdk8/spec/
But you can download bleeding edge versions of the OpenJDK 8 binaries today and play around with the lambda language construct and the current implementations in the collections libraries as well as a lot of the other libraries. http://jdk8.java.net/download.html
Alternative functional libraries
If you can't wait there are libraries for functional programming in Java that will work with JDK5 or newer.
Guava
Googles Guava libraries have support for functional idioms. However without language support the code easily becomes messed up with boilerplate. On the other hand, there are a lot of good stuff in Guava like a richer set of collection constructs and easier use of immutable collections types. Here
[code language="java"]Multiset lengths = HashMultiset.create(
FluentIterable.from(strings)
.filter(new Predicate() {
public boolean apply(String string) {
return CharMatcher.JAVA_UPPER_CASE.matchesAllOf(string);
}
})
.transform(new Function<String, Integer>() {
public Integer apply(String string) {
return string.length();
}
}));[/code]
Lambdaj
Another interesting library is Lambdaj which uses static imported methods to hide give a nicer looking syntax. This is some typical Java code to sort a list of persons according to age
[code language="java"]List sortedByAgePersons = new ArrayList(persons);
Collections.sort(sortedByAgePersons, new Comparator() {
public int compare(Person p1, Person p2) {
return Integer.valueOf(p1.getAge()).compareTo(p2.getAge());
}
});[/code]
With Lambdaj, you could express this as
[code language="java"]List sortedByAgePersons = sort(persons, on(Person.class).getAge());[/code]
Check out more features at http://code.google.com/p/lambdaj/wiki/LambdajFeatures.
FunctionalJava
FunctionalJava solves the syntax verbosity problem by using the Java 7 BGGA proposal syntax. This adds closures as a part of the language dialect. However, this requires a pass with a pre compiler to render compilable Java code.
This is an example of code that adds 42 to each element in the array.
[code language="java"]final Array a = array(1, 2, 3);
final Array b = a.map({int i => i + 42});
arrayShow(intShow).println(b); // {43,44,45}[/code]
Noteworthy is that solution also heavily relies on static imports. Check out more example at http://functionaljava.org/examples/1.5/
My thoughts
In the end though, due to the lack of anonymous functions in Java today, the best choice to program in a functional way is probably to stick to Scala, Clojure, Groovy or another of the JVM languages that has inherent support for this style until Java 8. With what we got today in Java you can still use many of the functional concepts like preferring immutable data, avoiding side effects and more.
The above mentioned alternatives are just a few of what's out there. But common among them are either that you must rely on preprocessing some functional dialect of Java to produce compilable Java code or to use a verbose syntax like Guava. In my opinion these tradeoffs effect on readability, maintainability and possibly portability just isn't worth it.
* The views expressed in this article are those of the author and do not necessarily represent the views of, and should not be attributed to, Jelastic or its technology and distribution partners.