Functional Interfaces
Before Java 8, passing a "behavior" or a "function" as an argument to a method was extremely difficult. You had to create an interface, write a class that implemented the interface, and then pass an object of that class.
Java 8 introduced Functional Interfaces to lay the groundwork for passing functions directly.
What is a Functional Interface?
A Functional Interface is simply an interface that contains exactly one abstract method. This is also known as the SAM (Single Abstract Method) rule.
It can contain any number of default or static methods, but it must have only one unimplemented, abstract method.
Example: A Custom Functional Interface
// Adding this annotation is optional, but highly recommended!
@FunctionalInterface
public interface MathOperation {
// Exactly ONE abstract method
int operate(int a, int b);
// It can have multiple default methods!
default void printResult(int result) {
System.out.println("The result is: " + result);
}
}
The @FunctionalInterface Annotation
This annotation is used to ensure at compile-time that the interface doesn't violate the SAM rule. If another developer comes along and accidentally adds a second abstract method to the interface, the compiler will instantly throw an error.
Built-in Functional Interfaces
You rarely need to write your own functional interfaces from scratch. Java 8 provides a massive suite of built-in functional interfaces in the java.util.function package.
Here are the 4 core types you will encounter everywhere (especially when using Streams):
| Interface | Method Signature | What it does | Common Use Case |
|---|---|---|---|
Predicate<T> | boolean test(T t) | Takes an object, evaluates a condition, returns true/false. | Filtering a list (e.g., "Is this number even?"). |
Function<T, R> | R apply(T t) | Takes an object of type T, transforms it, returns type R. | Mapping a list (e.g., converting a String to its Integer length). |
Consumer<T> | void accept(T t) | Takes an object, performs an action, returns nothing. | Printing elements (e.g., System.out.println). |
Supplier<T> | T get() | Takes nothing, returns an object. | Generating data (e.g., getting the current Date or a Random number). |
By themselves, Functional Interfaces are just rules. In the next section, we will see how to actually implement them instantly using Lambda Expressions.