Published: January 19, 2016
Introduction
Functional interfaces are a key part of Java 8’s functional programming capabilities. A functional interface is an interface that has exactly one abstract method, and it can have multiple default or static methods. The most significant use of functional interfaces is with lambda expressions, as they provide a target type for the expression.
In this tutorial, we’ll explore functional interfaces in detail and see how they are used in Java 8. We’ll also take a look at some of the built-in functional interfaces in the java.util.function
package.
What Is a Functional Interface?
A functional interface is an interface that has just one abstract method. Although it can have more than one method, only one abstract method is allowed. It can have any number of default or static methods.
In Java 8, functional interfaces are used primarily to represent lambda expressions and method references. Java 8 introduced the @FunctionalInterface
annotation, which can be used to indicate that an interface is intended to be a functional interface.
Example of a Functional Interface:
@FunctionalInterface
public interface MyFunctionalInterface {
void myMethod(); // This is the single abstract method
}
This interface MyFunctionalInterface
is a functional interface because it has exactly one abstract method (myMethod()
), and the annotation @FunctionalInterface
explicitly marks it as a functional interface.
Using Lambda Expressions with Functional Interfaces
Functional interfaces are ideal for use with lambda expressions. Since they have only one abstract method, lambda expressions can be used to implement that method.
Example of Using a Lambda with a Functional Interface:
@FunctionalInterface
public interface Greeting {
void greet(String name);
}
public class Main {
public static void main(String[] args) {
Greeting greeting = (name) -> System.out.println("Hello, " + name);
greeting.greet("Alice"); // Output: Hello, Alice
}
}
In this example, the Greeting
functional interface has a single method greet(String name)
. We use a lambda expression to provide the implementation of this method, which outputs a greeting message.
Common Built-in Functional Interfaces in Java 8
Java 8 introduced several functional interfaces in the java.util.function
package. These interfaces provide common functionalities that can be used in functional programming. Here are some of the most common functional interfaces:
1. Predicate<T>
A Predicate
is a functional interface that represents a condition or boolean-valued function. It takes a single argument of type T
and returns a boolean value.
Predicate<Integer> isEven = (n) -> n % 2 == 0;
System.out.println(isEven.test(4)); // Output: true
System.out.println(isEven.test(7)); // Output: false
2. Consumer<T>
A Consumer
represents an operation that takes a single input argument and returns no result. It’s typically used for operations like printing or modifying a value without returning anything.
Consumer<String> printName = (name) -> System.out.println("Name: " + name);
printName.accept("Alice"); // Output: Name: Alice
3. Function<T, R>
A Function
represents a function that takes an argument of type T
and produces a result of type R
. It can be used to transform data.
Function<String, Integer> stringLength = (s) -> s.length();
System.out.println(stringLength.apply("Hello")); // Output: 5
4. Supplier<T>
A Supplier
is a functional interface that represents a function that takes no arguments and returns a result. It’s commonly used for providing values lazily or generating random numbers.
Supplier<Double> randomValue = () -> Math.random();
System.out.println(randomValue.get()); // Output: Random number between 0.0 and 1.0
5. UnaryOperator<T>
A UnaryOperator
is a special case of Function
that takes a single argument of type T
and returns a result of the same type T
.
UnaryOperator<Integer> doubleValue = (n) -> n * 2;
System.out.println(doubleValue.apply(4)); // Output: 8
Custom Functional Interfaces
You can also create your own functional interfaces in Java. The only requirement is that the interface should have exactly one abstract method. If you have multiple abstract methods, you cannot use lambda expressions or method references with that interface.
Example of a Custom Functional Interface:
@FunctionalInterface
public interface MathOperation {
int operation(int a, int b);
}
public class Calculator {
public static void main(String[] args) {
MathOperation addition = (a, b) -> a + b;
MathOperation subtraction = (a, b) -> a - b;
System.out.println("Addition: " + addition.operation(10, 5)); // Output: 15
System.out.println("Subtraction: " + subtraction.operation(10, 5)); // Output: 5
}
}
In this example, we define a custom functional interface MathOperation
that has a single abstract method operation(int a, int b)
. We implement this method with lambda expressions for addition and subtraction.
Using Functional Interfaces in Java Collections
Functional interfaces are extremely useful in Java 8 when working with collections, especially with the Streams API. You can use lambdas or method references to filter, map, and process data in a concise and functional way.
For example:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
names.stream()
.filter(name -> name.startsWith("A"))
.forEach(System.out::println); // Output: Alice
Here, we use the Predicate
functional interface (via lambda expression) to filter names that start with the letter “A”, and then print those names.
Summary
In this tutorial, we have learned about functional interfaces, which are the foundation for lambda expressions in Java 8. We explored the built-in functional interfaces such as Predicate
, Function
, Consumer
, and Supplier
, and saw how they can be used to write more concise and expressive code.
Functional interfaces allow Java to support functional programming features, which help to write cleaner and more readable code. Understanding functional interfaces is essential for working with Java 8’s Streams API and other functional constructs.
Conclusion
Functional interfaces play a key role in Java 8’s functional programming features. By using lambda expressions and method references with functional interfaces, you can write cleaner, more modular, and more readable code. In the next tutorial, we’ll dive deeper into how to Write Your First Lambda Expression and see practical examples of lambda expressions in action.
Happy coding!