Supplier, Consumer, Predicate, Function¶
โ Java 17 ยท The Ready-Made Lambda Toolkit ยท 1/4
Instead of one-off interfaces like MovieCheck or TitleMaker, Java offers generic ones in java.util.function. Every Java developer recognizes them at a glance.
Supplier โ no input, one output¶
public interface Supplier<T> { T get(); }
Supplier<LocalDate> today = LocalDate::now;
Supplier<List<Movie>> lists = ArrayList::new;
System.out.println(today.get()); // e.g. 2026-10-05
List<Movie> watchlist = lists.get(); // a new, empty list
A natural factory: each get() produces a value. Print today instead of today.get() and you get a generated name with $$Lambda: the lambda object, not its result.
Consumer โ input, nothing returned¶
public interface Consumer<T> { void accept(T t); }
public interface BiConsumer<T, U> { void accept(T t, U u); }
Consumer<String> show = System.out::println;
show.accept("Stranger Things");
var ratings = new HashMap<String, Double>();
BiConsumer<String, Double> rate = ratings::put;
rate.accept("Dark", 8.7); // {Dark=8.7}
Bi means one more parameter: two inputs instead of one.
Predicate โ a yes-or-no question¶
public interface Predicate<T> { boolean test(T t); }
public interface BiPredicate<T, U> { boolean test(T t, U u); }
Predicate<String> blank = String::isBlank;
blank.test(" "); // true
BiPredicate<String, String> starts = String::startsWith;
starts.test("Narcos", "Nar"); // true
test() returns a primitive boolean, not a Boolean object.
Function โ turn one thing into another¶
public interface Function<T, R> { R apply(T t); }
public interface BiFunction<T, U, R> { R apply(T t, U u); }
Function<String, Integer> length = String::length;
length.apply("Wednesday"); // 9
BiFunction<String, String, String> join = String::concat;
join.apply("Squid ", "Game"); // Squid Game
The last type parameter is always the return type.
Operators โ same type in and out¶
UnaryOperator<String> shout = String::toUpperCase; // a Function<String, String>
BinaryOperator<String> merge = String::concat; // a BiFunction<String, String, String>
shout.apply("dark"); // DARK
merge.apply("The ", "Crown"); // The Crown
When every type is the same, the operator says it with one type parameter instead of two or three. The method is still apply().
Cheat sheet¶
| Interface | Method | Returns |
|---|---|---|
Supplier<T> |
get() |
T |
Consumer<T> / BiConsumer<T,U> |
accept(T) / accept(T,U) |
void |
Predicate<T> / BiPredicate<T,U> |
test(T) / test(T,U) |
boolean |
Function<T,R> / BiFunction<T,U,R> |
apply(T) / apply(T,U) |
R |
UnaryOperator<T> / BinaryOperator<T> |
apply(T) / apply(T,T) |
T |
To pick one: no input โ Supplier; nothing returned โ Consumer; a boolean โ Predicate; same type in and out โ Operator; otherwise โ Function. Two inputs โ the Bi version (or BinaryOperator).