Predicate / Function / Consumer / Supplier
These are the primary functional interfaces added in Java 8. They are used in combination with lambda expressions and method references, each serving one of four roles: testing, transforming, consuming, or supplying values.
Syntax
// Predicate<T>: Takes a T and returns a boolean.
Predicate<T> pred = (T t) -> /* boolean expression */;
boolean result = pred.test(t);
// Function<T, R>: Takes a T and returns an R.
Function<T, R> func = (T t) -> /* value of type R */;
R result = func.apply(t);
// Consumer<T>: Takes a T and returns nothing.
Consumer<T> cons = (T t) -> { /* process */ };
cons.accept(t);
// Supplier<T>: Takes no arguments and returns a T.
Supplier<T> supp = () -> /* value of type T */;
T value = supp.get();
// BiFunction<T, U, R>: Takes two arguments and returns an R.
BiFunction<T, U, R> bif = (T t, U u) -> /* value of type R */;
// UnaryOperator<T>: Takes a T and returns a T of the same type.
UnaryOperator<T> op = (T t) -> /* value of type T */;
Common Functional Interfaces
| Interface | Abstract Method | Description |
|---|---|---|
| Predicate<T> | test(T t) → boolean | Used for condition testing. Passed to stream operations like filter(). |
| Function<T, R> | apply(T t) → R | Transforms a value. Passed to stream operations like map(). |
| Consumer<T> | accept(T t) → void | Accepts a value and processes it without returning anything. Passed to operations like forEach(). |
| Supplier<T> | get() → T | Produces and returns a value with no arguments. Used for lazy evaluation. |
| BiFunction<T, U, R> | apply(T t, U u) → R | Accepts two arguments and returns a value. |
| BiConsumer<T, U> | accept(T t, U u) → void | Accepts two arguments and processes them. Passed to operations like Map.forEach(). |
| UnaryOperator<T> | apply(T t) → T | Performs a transformation within the same type. A specialization of Function<T,T>. |
| BinaryOperator<T> | apply(T t, T u) → T | Accepts two arguments of the same type and returns the same type. Passed to operations like reduce(). |
Sample Code
import java.util.*;
import java.util.function.*;
// Predicate: Tests whether a number is even.
Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(4)); // Prints "true".
System.out.println(isEven.test(7)); // Prints "false".
// Composing Predicates: Combine with and() / or() / negate().
Predicate<Integer> isPositive = n -> n > 0;
Predicate<Integer> isEvenAndPositive = isEven.and(isPositive);
System.out.println(isEvenAndPositive.test(4)); // Prints "true".
System.out.println(isEvenAndPositive.test(-2)); // Prints "false".
// Function: Converts a string to uppercase.
Function<String, String> toUpper = String::toUpperCase;
System.out.println(toUpper.apply("hello")); // Prints "HELLO".
// Composing Functions: Chain with andThen().
Function<String, Integer> toLength = String::length;
Function<String, Integer> upperLength = toUpper.andThen(toLength);
System.out.println(upperLength.apply("hello")); // Prints "5".
// Consumer: Prints each element in a list.
Consumer<String> printer = s -> System.out.println("> " + s);
List.of("A", "B", "C").forEach(printer);
// Supplier: Lazily creates a default value.
Supplier<List<String>> listFactory = ArrayList::new;
List<String> newList = listFactory.get();
newList.add("item");
System.out.println(newList); // Prints "[item]".
Notes
These interfaces are part of the java.util.function package and are used as the target types for lambda expressions and method references. They are also widely used in the Stream API and Optional, so learning them will be very useful.
Predicate supports composition via and() / or() / negate(), and Function supports composition via andThen() / compose(). Using primitive-specialized variants such as IntPredicate, IntFunction<R>, IntConsumer, and IntSupplier avoids the cost of autoboxing.
For how to write lambda expressions, see 'Lambda Expressions / (x) -> x * 2'.
If you find any errors or copyright issues, please contact us.