Introduction
Java 8 introduced Functional Interfaces, a core feature that enables functional programming in Java. Functional interfaces are used extensively in Lambda Expressions and Stream API, making Java code more concise and readable.
What is a Functional Interface?
A Functional Interface is an interface that contains only one abstract method, though it may have multiple default or static methods. Java 8 introduced the @FunctionalInterface
annotation to ensure that an interface adheres to this rule.
Example of a Functional Interface
@FunctionalInterface
interface MyFunctionalInterface {
void display();
}
Here, MyFunctionalInterface
has only one abstract method (display()
), making it a functional interface.
Built-in Functional Interfaces in Java 8
Java 8 provides several built-in functional interfaces in the java.util.function
package. The most commonly used ones are:
1. Predicate (T → boolean)
Represents a function that takes an input and returns a boolean result. Useful for filtering collections.
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args) {
Predicate<Integer> isEven = num -> num % 2 == 0;
System.out.println(isEven.test(4)); // true
}
}
2. Function<T, R> (T → R)
Represents a function that takes an input of type T
and returns a result of type R
.
import java.util.function.Function;
public class FunctionExample {
public static void main(String[] args) {
Function<String, Integer> stringLength = str -> str.length();
System.out.println(stringLength.apply("Java")); // 4
}
}
3. Consumer (T → void)
Represents a function that takes an input and performs an operation without returning any value.
import java.util.function.Consumer;
public class ConsumerExample {
public static void main(String[] args) {
Consumer<String> printMessage = msg -> System.out.println(msg);
printMessage.accept("Hello, Java 8!"); // Output: Hello, Java 8!
}
}
4. Supplier (() → T)
Represents a function that does not take any input but returns a value.
import java.util.function.Supplier;
public class SupplierExample {
public static void main(String[] args) {
Supplier<Double> randomNumber = () -> Math.random();
System.out.println(randomNumber.get());
}
}
5. BinaryOperator (T, T → T)
Represents a function that takes two inputs of the same type and returns a result of the same type.
import java.util.function.BinaryOperator;
public class BinaryOperatorExample {
public static void main(String[] args) {
BinaryOperator<Integer> sum = (a, b) -> a + b;
System.out.println(sum.apply(5, 10)); // 15
}
}
Custom Functional Interface with Lambda Expression
You can create your own functional interfaces and use them with lambda expressions.
@FunctionalInterface
interface Calculator {
int operate(int a, int b);
}
public class CustomFunctionalInterface {
public static void main(String[] args) {
Calculator addition = (a, b) -> a + b;
System.out.println(addition.operate(10, 20)); // 30
}
}
Using Functional Interfaces with Streams
Functional interfaces are commonly used in Java Streams for operations like filtering, mapping, and reducing.
import java.util.Arrays;
import java.util.List;
public class StreamExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Jane", "Jack", "Jill");
names.stream()
.filter(name -> name.startsWith("J"))
.forEach(System.out::println);
}
}
Conclusion
Java 8 Functional Interfaces enable functional programming by allowing the use of lambda expressions and method references. Understanding these interfaces helps write concise, readable, and efficient code. Built-in interfaces like Predicate
, Function
, Consumer
, Supplier
, and BinaryOperator
are useful for various scenarios. If you’re working with Java 8 or later, adopting functional interfaces can greatly improve your programming efficiency!