Introduction
Java 8 introduced functional interfaces and lambda expressions, transforming the way developers write and approach Java code. A functional interface is an interface with a single abstract method, allowing for more streamlined and functional programming. This article will guide you through the concept of functional interfaces, their significance, and provide step-by-step examples to illustrate their usage.
What is a Functional Interface?
A functional interface in Java is an interface that contains only one abstract method. These interfaces are designed to facilitate the use of lambda expressions and method references, making your code more concise and readable. Functional interfaces are marked with the @FunctionalInterface
annotation, which is optional but highly recommended as it helps the compiler enforce the single abstract method rule.
Built-in Functional Interfaces

Java 8 provides a set of built-in functional interfaces in the java.util.function
package. Some of the most commonly used ones include:
- Predicate: Represents a boolean-valued function of one argument.
- Function: Represents a function that takes one argument and produces a result.
- Consumer: Represents an operation that accepts a single input argument and returns no result.
- Supplier: Represents a supplier of results.
Here’s a comparison table summarizing the differences between Predicate
, Function
, Consumer
, and Supplier
:
Interface | Purpose | Method(s) | Input Type | Output Type | Typical Use Cases |
---|---|---|---|---|---|
Predicate | Evaluates a condition and returns a boolean | boolean test(T t) | T | boolean | Filtering collections, validation checks |
Function | Transforms an input of type T to a result of type R | R apply(T t) | T | R | Mapping values, transforming data |
Consumer | Accepts an input and performs an action without returning a result | void accept(T t) | T | void | Performing side effects, processing elements |
Supplier | Provides a result of type T without requiring any input | T get() | void | T | Generating values, supplying instances |
Step-by-Step Examples
1. Using Predicate Functional Interface
The Predicate
interface is used for testing a condition. It has a single abstract method test
that returns a boolean.
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args) {
Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(4)); // true
System.out.println(isEven.test(5)); // false
}
}
2. Using Function Functional Interface
The Function
interface represents a function that accepts one argument and produces a result. It has a single abstract method apply
.
import java.util.function.Function;
public class FunctionExample {
public static void main(String[] args) {
Function<String, Integer> lengthFunction = s -> s.length();
System.out.println(lengthFunction.apply("Hello")); // 5
System.out.println(lengthFunction.apply("Lambda")); // 6
}
}
3. Using Consumer Functional Interface
The Consumer
interface represents an operation that accepts a single input argument and returns no result. It has a single abstract method accept
.
import java.util.function.Consumer;
public class ConsumerExample {
public static void main(String[] args) {
Consumer<String> printConsumer = s -> System.out.println(s);
printConsumer.accept("Hello, World!"); // Hello, World!
printConsumer.accept("Java 8"); // Java 8
}
}
4. Using Supplier Functional Interface
The Supplier
interface represents a supplier of results. It has a single abstract method get
.
import java.util.function.Supplier;
public class SupplierExample {
public static void main(String[] args) {
Supplier<String> helloSupplier = () -> "Hello, Supplier!";
System.out.println(helloSupplier.get()); // Hello, Supplier!
}
}
Custom Functional Interfaces
You can also create your own functional interfaces by ensuring they contain only one abstract method. Annotating them with @FunctionalInterface
is a good practice.
@FunctionalInterface
interface MyFunctionalInterface {
void myMethod();
}
public class CustomFunctionalInterfaceExample {
public static void main(String[] args) {
MyFunctionalInterface myInterface = () -> System.out.println("Custom Functional Interface");
myInterface.myMethod(); // Custom Functional Interface
}
}
Chaining Functional Interfaces
Functional interfaces can be chained together to create complex operations.
import java.util.function.Function;
public class ChainingExample {
public static void main(String[] args) {
Function<Integer, Integer> multiplyByTwo = n -> n * 2;
Function<Integer, Integer> square = n -> n * n;
Function<Integer, Integer> multiplyAndSquare = multiplyByTwo.andThen(square);
System.out.println(multiplyAndSquare.apply(3)); // 36 ((3 * 2) ^ 2)
}
}
Conclusion
Functional interfaces are a cornerstone of functional programming in Java. They enable developers to write more concise, readable, and expressive code. By understanding and utilizing built-in functional interfaces like Predicate
, Function
, Consumer
, and Supplier
, as well as creating custom functional interfaces, you can significantly enhance the efficiency and clarity of your Java applications.
The introduction of functional interfaces, combined with lambda expressions, represents a significant step forward in the evolution of Java, making it a more modern and versatile language for developers.