these declarations do not make the methods abstract. (Some interfaces in the Java API redeclare Object methods in order to attach
javadoc comments. Check out the Comparator API for an example.) More importantly, as you will see in Section 1.7 , “Default
Methods ,” on page 14 , in Java 8, interfaces can declare nonabstract methods.
To demonstrate the conversion to a functional interface, consider the Arrays.sort method. Its second parameter requires an instance of
Comparator , an interface with a single method. Simply supply a lambda:
Click here to view code image
Arrays.sort(words,
(first, second) -> Integer.compare(first.length(), second.length()));
Behind the scenes, the Arrays.sort method receives an object of some class that implements Comparator<String> . Invoking the compare
method on that object executes the body of the lambda expression. The management of these objects and classes is completely implementation
dependent, and it can be much more efficient than using traditional inner classes. It is best to think of a lambda expression as a function, not an
object, and to accept that it can be passed to a functional interface.
This conversion to interfaces is what makes lambda expressions so compelling. The syntax is short and simple. Here is another example:
Click here to view code image
button.setOnAction(event ->
System.out.println("Thanks for clicking!"));
That’s a lot easier to read than the alternative with inner classes.
In fact, conversion to a functional interface is the only thing that you can do with a lambda expression in Java. In other programming languages that
support function literals, you can declare function types such as (String, String) -> int , declare variables of those types, and use the
variables to save function expressions. However, the Java designers decided to stick with the familiar concept of interfaces instead of adding
function types to the language.
NOTE
You can’t even assign a lambda expression to a variable of type Object —Object is not a functional interface.
The Java API defines a number of very generic functional interfaces in the java.util.function package. (We will have a closer look at these
interfaces in Chapters 2 and 3 .) One of the interfaces, BiFunction<T, U, R> , describes functions with parameter types T and U and return
type R . You can save our string comparison lambda in a variable of that type:
Click here to view code image
BiFunction<String, String, Integer> comp
= (first, second) -> Integer.compare(first.length(), second.length());
However, that does not help you with sorting. There is no Arrays.sort method that wants a BiFunction . If you have used a functional
programming language before, you may find this curious. But for Java programmers, it’s pretty natural. An interface such as Comparator has a
specific purpose, not just a method with given parameter and return types. Java 8 retains this flavor. When you want to do something with lambda
expressions, you still want to keep the purpose of the expression in mind, and have a specific functional interface for it.
The interfaces in java.util.function are used in several Java 8 APIs, and you will likely see them elsewhere in the future. But keep in mind
that you can equally well convert a lambda expression into a functional interface that is a part of whatever API you use today.
NOTE
You can tag any functional interface with the @FunctionalInterface annotation. This has two advantages. The compiler checks
that the annotated entity is an interface with a single abstract method. And the javadoc page includes a statement that your interface is
a functional interface.
It is not required to use the annotation. Any interface with a single abstract method is, by definition, a functional interface. But using
the @FunctionalInterface annotation is a good idea.