Functional Interfaces
TL;DR
- A Functional Interface is an interface that contains exactly one abstract method.
- They are the foundation of Java’s Lambda Expressions and Streams API.
- The
@FunctionalInterfaceannotation is optional but recommended to enforce the single-method rule at compile time.
Concept
In Java, passing behavior (a function) to another method used to be incredibly verbose using Anonymous Inner Classes.
Java 8 introduced Lambdas (->) to solve this. But Java is strongly typed; what is the “Type” of a Lambda expression?
The answer is a Functional Interface. A Lambda is simply a shorthand, dynamic implementation of that single abstract method.
(Note: A Functional Interface can have infinite default or static methods, as long as there is only ONE abstract method).
Examples
// 1. Define a Functional Interface
@FunctionalInterface
public interface MathOperation {
int operate(int a, int b); // Exactly ONE abstract method
// Default methods are perfectly fine!
default void printResult(int result) {
System.out.println("Result: " + result);
}
}
public class FunctionalDemo {
public static void main(String[] args) {
// 2. Use a Lambda expression to implement the interface on the fly
MathOperation addition = (a, b) -> a + b;
MathOperation multiplication = (a, b) -> a * b;
addition.printResult( addition.operate(5, 3) ); // 8
multiplication.printResult( multiplication.operate(5, 3) ); // 15
}
}
Interview Questions
Q: What are the core built-in Functional Interfaces in java.util.function?
A: Java provides dozens, but they stem from four main types:
Predicate<T>: Takes an input, returns aboolean(Used instream.filter()).Function<T, R>: Takes an input, transforms it, returns a result (Used instream.map()).Consumer<T>: Takes an input, returns nothing/void (Used instream.forEach()).Supplier<T>: Takes no input, returns a value (Used inOptional.orElseGet()).
Q: Why is the @FunctionalInterface annotation used?
A: It is purely a compiler safeguard. An interface with exactly one abstract method is technically a functional interface even without the annotation. However, if you add the annotation, the compiler will aggressively throw an error if another developer accidentally tries to add a second abstract method to it later, preventing them from breaking all the Lambda expressions across the codebase that rely on it.