🚀 What is a Functional Interface in Java?
A functional interface is a special type of interface in Java that contains exactly one abstract method (though it can have multiple default or static methods). This makes it eligible to be used with lambda expressions and method references.
🔖 Example
@FunctionalInterface
public interface MyFunctionalInterface {
void doSomething(); // Single abstract method (SAM)
}
This can be used like:
MyFunctionalInterface func = () -> System.out.println("Doing something!");
func.doSomething();
📜 Why Functional Interfaces?
Backstory: Before Java 8
- Before Java 8, if you wanted to pass behavior (a piece of code) into a method, you needed to define full classes, anonymous inner classes, or use external strategies.
- This was verbose and didn’t align well with the functional programming style.
Java 8 introduced:
✅ Functional Interfaces (with @FunctionalInterface
annotation).
✅ Lambda Expressions (simplified syntax to pass behavior directly).
✅ This enabled cleaner, more expressive functional programming in Java.
🎯 Key Rules for Functional Interfaces
Rule | Explanation |
---|---|
Exactly 1 abstract method | This defines the core “function” the interface represents. |
Can have default and static methods | These don’t count as abstract methods. |
Optional @FunctionalInterface annotation | This helps catch accidental mistakes (like adding a second abstract method). |
Compatible with lambdas and method references | This is the whole point — they work seamlessly with modern functional syntax. |
✅ Common Built-in Functional Interfaces (java.util.function)
Interface | Method | Purpose |
---|---|---|
Function<T, R> | R apply(T t) | Takes a value and returns a result. |
Consumer<T> | void accept(T t) | Takes a value and returns nothing. |
Supplier<T> | T get() | Supplies a value, takes nothing. |
Predicate<T> | boolean test(T t) | Tests a condition and returns boolean. |
BiFunction<T, U, R> | R apply(T t, U u) | Takes 2 inputs and returns a result. |
🌟 Example Usage (Lambda)
Predicate<String> isEmpty = s -> s.isEmpty();
System.out.println(isEmpty.test("")); // true
🔗 Example with Method Reference
Consumer<String> printer = System.out::println;
printer.accept("Hello from method reference!"); // Prints the message
📢 Why @FunctionalInterface
Annotation?
This annotation is optional but highly recommended because:
- It makes your intention clear to the compiler and other developers.
- If someone accidentally adds a second abstract method, the compiler will throw an error.
Example:
@FunctionalInterface
interface MyFunctional {
void doWork();
// Adding another abstract method here would cause a compile-time error
}
🔥 Quick Recap
✅ | Functional Interface Features |
---|---|
✔️ | Exactly one abstract method |
✔️ | Works with lambdas and method references |
✔️ | Supports default and static methods |
✔️ | Optional @FunctionalInterface annotation (recommended) |
✔️ | Core part of functional programming in modern Java |