What are the core functional interfaces in java.util.function (Function, Predicate, Supplier, Consumer)?
Quick Answer
Function<T,R> takes a T and returns an R (a transformation). Predicate<T> takes a T and returns boolean (a test/filter condition). Supplier<T> takes nothing and returns a T (a lazy value source/factory). Consumer<T> takes a T and returns nothing (an action performed on a value). Together they cover most shapes of behavior passed as arguments throughout the Stream API and modern JDK methods.
Detailed Answer
java.util.function defines a small set of general-purpose functional interfaces covering the most common "shapes" of behavior, so you rarely need to declare your own:
| Interface | Method | Signature shape | Typical use |
|---|---|---|---|
Function<T, R> | R apply(T t) | takes one, returns a (possibly different) type | transforming a value |
Predicate<T> | boolean test(T t) | takes one, returns boolean | filtering / conditions |
Supplier<T> | T get() | takes nothing, returns a value | lazy value creation / factories |
Consumer<T> | void accept(T t) | takes one, returns nothing | performing an action on a value |
BiFunction<T,U,R> | R apply(T t, U u) | two inputs, one output | combining two values |
UnaryOperator<T> | T apply(T t) | Function<T,T> specialization | transform within the same type |
BinaryOperator<T> | T apply(T a, T b) | BiFunction<T,T,T> specialization | reduction/combining, same type |
Function<String, Integer> length = String::length;
Predicate<String> isLong = s -> s.length() > 5;
Supplier<List<String>> newList = ArrayList::new;
Consumer<String> printer = System.out::println;
list.stream()
.filter(isLong) // Predicate
.map(length) // Function
.forEach(printer::accept); // Consumer
Optional.ofNullable(cachedValue)
.orElseGet(newList); // Supplier — lazily creates only if needed
Most also have default combinator methods for composing behavior without writing a new lambda from scratch — e.g., Predicate.and()/or()/negate(), Function.andThen()/compose(). There are also primitive-specialized variants (IntPredicate, ToIntFunction<T>, IntSupplier, ...) to avoid autoboxing overhead in numeric-heavy code.