Brian Goetz has published an updated state of the lambda, giving a status report on the plan for adding lambdas to the Java language (also being tracked as JSR 335 and Java Enhancement Proposal number 126.
The plan to bring lambdas to the Java language covers both the syntax for anonymous functions, as well as plans to extend the existing set of Java classes (such as Collections) with methods that accept lambdas as well. The goal is to add functions like map
and filter
to allow collections to be processed in a more functional way.
In order to retrofit these on existing interfaces (and not just the core Java classes), a new type of method has been added to interfaces called default methods (previously called defender methods in earlier versions). These effectively allow an interface to carry method implementations, much like Scala's traits or an abstract class would. When invoking a default method, if the compiler will initially delegate to the instance, but if a method is not found in the course of normal method resolution, the default method will be invoked instead. Unlike earlier revisions, instead of being a pointer to an existing class' static method, the new specification permits methods (but not fields) as valid interface bodies – albeit identified with the default
keyword. The example given is that of adding a skip()
method to all iterators:
interface Iterator<E> {
boolean hasNext();
E next();
void remove();
void skip(int i) default {
for (; i > 0 && hasNext(); i--) next();
}
}
Since this is effectively adding multiple inheritance of behavior to the Java language, in the case of a collision (where the same default method is inherited by two separate paths) the method must be overridden in that class, or one of the default methods explicitly selected via a new Iterator.super.skip()
construct.
Another recent change is the proposed syntax change for method references, from a JavaDoc-inspired Person#compare
to a more C++ inspired Person::compare
. Whatever the syntax, the method reference gives a way of effectively providing a typechecked shortcut to a Method to pas around into a lambda capturing method.
Although the actual lambda expressions haven't changed that much, some of the syntax parts and terminology has been recently revised. For example, whereas the previous decision was to use =>
, used by both C# and Scala as the syntax for introducing a lambda expression, the syntax has been updated to be ->
instead. So a function which now returns the negation of itself might be written int a -> a+1
. (If the type is able to be inferred, then it is used instead; in the case of this expression however the compiler cannot know if we mean a
to be a byte
, short
, int
or long
, so we must disambiguate explicitly.)
Another terminology change is the idea of classes like Runnable
and Action
. These are interfaces with a single abstract method, formerly called SAM types. To support the wider use of them in Java, these are now known as functional interfaces. The reason for this change is to encourage the use of these as being up-castable from a method reference; so where an existing Java codebase has methods which expect Comparator
instances, you can now pass in a lambda expression (or method handle) which has the same signature as Comparator's compareTo
method. Although technically, Comparator has two abstract methods (compareTo()
and, for some reason, equals()
), this is still seen as a functional interface as equals()
is already available on Object
.
Although function types were considered (and available in an earlier draft) they have been rejected – at least, for now – due to difficulties with function type erasure causing problems in the current version of the JVM. Although this doesn't rule it out in the future, the expectation is that the type-based functional interfaces will be more immediately useful both to Java and existing Java classes than a new functional type would be.
Lambdas continue to have an advantage in that the argument types can be inferred without having to be explicitly typed (unless there is a disambiguation needed, as above). Lambdas can also be recursive and capture state from their enclosing scope (lambdas, like inner classes, which capture enclosing scope are known as closures) – although that capture is only for final
variables, again like inner classes. However, the introduction of effectively final means that the final
can be inferred in most places and need not be explicitly mentioned.
The addition of lambdas to the Java language, along with method references, will significantly reduce the amount of boilerplate needed for common operations. For example, in order to sort an Array of Strings with case-insensitive comparison, you will be able to do:
Arrays.sort(names, String::compareToIgnoreCase)
Together with default methods, which enable interfaces to grow (like Scala's traits) without affecting existing code, writing Java code will be much more concise. A fully functional-object hybrid it isn't, but the foundations will see the rise of a number of functional-style libraries available for JDK8 and beyond. And whilst code compiled with lambdas and default methods won't be runnable on anything older than JDK8, it will permit the use of code compiled against older versions of the JDK to run, and be used in a functional way, in much the same way that generic types were slowly brought into the Java language.