We've always had functional interfaces before JDK8 but no lambdas, method references etc.
As of JDK8, they provide a target type for lambda expressions, method references and in turn, have better readability and more compact code.
Example, prior to Java-8 if you wanted to provide some logic that will be executed each time a Button
component is clicked you'd do:
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
This is bulky, hard to read and not compact enough. because EventHandler
is by definition a functional interface i.e. it has a SAM
as of jdk8 you can now do:
btn.setOnAction(event -> System.out.println("Hello World!"));
You only see the part of the code you care about i.e. the logic to be executed when the button is clicked.
Further, due to the fact that we can use functional interfaces as target types for lambda expressions & methods references, this would be useful when:
- passing a comparator to a sort method e.g.
List.sort
, Stream.sorted
, Collections.sort
etc.
- passing a block of code to run a task in a separate thread
etc...
while keeping the code readable, compact and concise.
Functional interfaces are used extensively in the Java-stream API.
There's no reason for you to create your own functional interface except there's not one that meets your requirements from java.util.function
or the name of the functional interface is not as readable so thus you may create your own.
There's also a @FunctionalInterface
annotation recommended to be used but not required whenever you're creating a functional interface (the standard library uses this a lot).
This enables the compiler to check that the annotated entity is an interface with a single abstract method otherwise gives an error.
This is also quite helpful in being able to catch errors when refactoring your code.