Lambda Expressions and Streams – Functional Interfaces
Understanding Functional Interfaces
Functional interfaces are a fundamental concept in Java when working with lambda expressions and streams. A functional interface is an interface that has exactly one abstract method. They play a key role in enabling the use of lambda expressions, which provide a concise way to define and implement single-method interfaces.
In Java, functional interfaces are used extensively with lambda expressions to make code more readable, expressive, and concise. The `java.util.function` package provides a set of predefined functional interfaces that are commonly used in lambda expressions and streams.
The `Consumer` Functional Interface
The `Consumer` functional interface represents an operation that takes an input and performs some action on it. It defines a single method called `accept(T t)` that takes an argument of type `T` and returns `void`. This interface is commonly used when you need to consume or process elements in a collection or stream.
Here’s an example of using the `Consumer` interface with a lambda expression to print elements of a list:
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
public class FunctionalInterfacesExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// Using a lambda expression with Consumer
Consumer<String> printName = (name) -> System.out.println("Hello, " + name);
names.forEach(printName);
}
}
In this code, we create a `Consumer` lambda expression `printName` that prints a greeting for each name in the list.
The `Predicate` Functional Interface
The `Predicate` functional interface represents a condition that can be applied to an input. It defines a single method called `test(T t)` that takes an argument of type `T` and returns a `boolean`. This interface is commonly used to filter elements in a collection or stream based on a specified condition.
Here’s an example of using the `Predicate` interface with a lambda expression to filter even numbers from a list of integers:
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class FunctionalInterfacesExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
// Using a lambda expression with Predicate
Predicate<Integer> isEven = (n) -> n % 2 == 0;
numbers.stream()
.filter(isEven)
.forEach(System.out::println);
}
}
In this code, we create a `Predicate` lambda expression `isEven` to check if a number is even, and then we use it with the `filter` method to extract even numbers from the list.
The `Function` Functional Interface
The `Function` functional interface represents a function that takes an input of type `T` and returns a result of type `R`. It defines a single method called `apply(T t)` to perform the transformation. This interface is often used to map elements in a collection or stream from one type to another.
Here’s an example of using the `Function` interface with a lambda expression to convert a list of strings to uppercase:
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
public class FunctionalInterfacesExample {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "cherry");
// Using a lambda expression with Function
Function<String, String> toUpperCase = (word) -> word.toUpperCase();
words.stream()
.map(toUpperCase)
.forEach(System.out::println);
}
}
In this code, we create a `Function` lambda expression `toUpperCase` to convert words to uppercase, and then we use it with the `map` method to perform the transformation.
Conclusion
Functional interfaces are a crucial part of modern Java programming, enabling the use of lambda expressions and stream operations. Understanding common functional interfaces like `Consumer`, `Predicate`, and `Function` empowers developers to write clean and expressive code with greater ease and conciseness.