Card 04/ 09
Function vs Predicate vs Consumer vs Supplier
Four interfaces cover almost every lambda, separated by whether it takes something and whether it gives something back.
The package java.util.function ships general-purpose functional interfaces so you rarely write your own. Four cover almost everything, and two questions separate them: does it take a value, and does it give one back?
| Interface | Takes | Gives back | The method | Written as |
|---|---|---|---|---|
Function<T, R> | A T | An R | apply | s -> s.length() |
Predicate<T> | A T | A boolean | test | s -> s.isBlank() |
Consumer<T> | A T | Nothing | accept | s -> System.out.println(s) |
Supplier<T> | Nothing | A T | get | () -> new ArrayList<>() |
The decision rule. Work out what goes in and what comes out and the interface is decided. A Predicate is only a Function that returns a boolean, and it exists separately because filtering is common enough to deserve a name and and, or and negate to combine with.
Two variants turn up constantly. BiFunction<T, U, R> takes two arguments, and UnaryOperator<T> is a Function whose input and output are the same type, which is what List.replaceAll wants.
So when a method signature takes one of these, it is telling you the shape of the lambda, the inline function, to write: a Predicate<Invoice> wants invoice -> something true or false, and a Supplier<List<Invoice>> wants () -> a new list.
← → move through sections and cards