Working with Functional Interfaces
1. Using Predicate<T>
| Method | Use |
|---|---|
test(T) | Returns boolean |
and(other) | Logical AND |
or(other) | Logical OR |
negate() | Logical NOT |
Predicate.isEqual(o) | Equality predicate |
Predicate.not(p) JAVA 11+ | Static negation |
2. Using Function<T,R>
Example: Function composition
Function<String, Integer> len = String::length;
Function<Integer, Integer> sq = x -> x * x;
Function<String, Integer> lenSquared = len.andThen(sq); // len → sq
Function<String, Integer> squareLen = sq.compose(len); // len → sq
| Method | Use |
|---|---|
apply(T) | Returns R |
andThen(after) | Apply this, then after |
compose(before) | Apply before, then this |
identity() | Returns input unchanged |
3. Using Consumer<T>
| Method | Use |
|---|---|
accept(T) | Side-effect, returns void |
andThen(after) | Chain consumers |
4. Using Supplier<T>
| Method | Use |
|---|---|
get() | Produces T (no input) |
| Common | Lazy init, default value providers |
5. Using UnaryOperator<T>
| Aspect | Detail |
|---|---|
| Extends | Function<T,T> |
| Use | Same input/output type (e.g., list.replaceAll) |
identity() | Static factory |
6. Using BinaryOperator<T>
| Aspect | Detail |
|---|---|
| Extends | BiFunction<T,T,T> |
| Factories | minBy(cmp), maxBy(cmp) |
| Use | Reductions, accumulators |
7. Using BiPredicate<T,U>
| Method | Use |
|---|---|
test(T, U) | Returns boolean |
and/or/negate | Combinators |
8. Using BiFunction<T,U,R>
| Method | Use |
|---|---|
apply(T, U) | Returns R |
andThen(fn) | Chain Function on result |
9. Using BiConsumer<T,U>
| Method | Common Use |
|---|---|
accept(T, U) | Map.forEach, side-effects on pairs |
10. Creating Custom Functional Interfaces
Example: Custom interface
@FunctionalInterface
interface ThrowingFunction<T, R, E extends Exception> {
R apply(T input) throws E;
}
ThrowingFunction<String, Integer, IOException> reader =
s -> Files.readString(Path.of(s)).length();
| Use Case | Detail |
|---|---|
| Checked exceptions | Standard interfaces don't allow them |
| Domain-specific | Clearer than generic Function |
11. Combining Predicates
Example: Predicate composition
Predicate<String> nonNull = Objects::nonNull;
Predicate<String> nonEmpty = s -> !s.isEmpty();
Predicate<String> valid = nonNull.and(nonEmpty);
users.stream().filter(Predicate.not(User::isBlocked)).toList();
| Combinator | Result |
|---|---|
p1.and(p2) | Both true |
p1.or(p2) | Either true |
p.negate() | Inverted |
12. Composing Functions
| Method | Order |
|---|---|
f.andThen(g) | g(f(x)) |
f.compose(g) | f(g(x)) |