Java
Summary - Functional interface
Combine Function, Predicate and Consumer to write a stream processor.
Summary - Functional interface
In this group you met the four core functional interfaces and the @FunctionalInterface annotation. Function transforms, Predicate returns a condition, Consumer consumes, Supplier produces. All have a single abstract method and can be written as lambdas.
Combining these interfaces yields short, readable code. For example you pass a Predicate to filter, a Function to map and a Consumer to forEach. This is the standard way to express stream operations in a single line.
Exercise Function + Predicate + Consumer chain
Define a Function<String, Integer> len = String::length. Define a Predicate<Integer> big = n -> n > 4. Loop over List.of("pen", "desk", "notebook"); when big.test(len.apply(w)) is true, print w with System.out.println.
Show example solution
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
public class ChainFunctional {
public static void main(String[] args) {
Function<String, Integer> len = String::length;
Predicate<Integer> big = n -> n > 4;
for (String w : List.of("pen", "desk", "notebook")) {
if (big.test(len.apply(w))) {
System.out.println(w);
}
}
}
}
When to define a custom interface?
In most cases the interfaces in java.util.function are enough. You define a custom interface only when the function has a specific meaning or when the primitive variants do not fit.
For example a User -> boolean condition is usually carried as Predicate<User>. But if writing Predicate<User> everywhere hurts readability, defining @FunctionalInterface interface UserRule may be cleaner. The choice depends on the long-term readability of the code.
Exercise Define and use a custom StringOp interface
Define a StringOp interface with @FunctionalInterface; it should have a String transform(String input) method. In main, assign the String::toUpperCase method reference to a StringOp variable. Print the result of transform("hello") with System.out.println.
Show example solution
@FunctionalInterface
interface StringOp {
String transform(String input);
}
public class CustomStringOp {
public static void main(String[] args) {
StringOp upper = String::toUpperCase;
System.out.println(upper.transform("hello"));
}
}
Test yourself
-
Which interface takes a value and returns void?
- Function<T,R>
- Consumer<T>
- Predicate<T>
- Supplier<T>
Show answer
Consumer<T> — Consumer<T> consumes the value and returns void.
-
Match each interface with its behavior
- Function<T,R>
- Transforms
- Predicate<T>
- Returns a condition
- Consumer<T>
- Consumes
- Supplier<T>
- Produces
Next lesson: LocalDate