Summary - Functional interface
- Java course
- Advanced
- Lesson 18/82
- 5 min
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.
Practice 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.
Starter code
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
// Define length Function and condition Predicate
// Loop and print based on the conditionSample 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);
}
}
}
}Expected output
desk notebook
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.
Practice 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.
Starter code
// Define the StringOp interface (one abstract method)
// Its transform method takes and returns a String
// In main, use upper, print the resultSample 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"));
}
}Expected output
HELLO
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Which interface takes a value and returns void?
- Function<T,R>
- Consumer<T> Correct answer
- Predicate<T>
- Supplier<T>
Explanation: Consumer<T> consumes the value and returns void.
2 Match each interface with its behavior
| Term | Meaning |
|---|---|
Function<T,R> |
Transforms |
Predicate<T> |
Returns a condition |
Consumer<T> |
Consumes |
Supplier<T> |
Produces |