Functional Programming & Streams

Standard Functional Interfaces

java.util.function supplies the vocabulary of functional Java: Function, Predicate, Consumer, Supplier, the two-arg Bi* forms, operators, and primitive specializations. Use these instead of inventing your own (EJ 44).
  • Six core shapes: Function<T,R>, Predicate<T>, Consumer<T>, Supplier<T>, UnaryOperator<T>, BinaryOperator<T>
  • Primitive specializations (IntPredicate, LongFunction…) avoid boxing — prefer them
  • Composition: f.andThen(g), f.compose(g), p.and(q).or(r), p.negate()
  • Write your own only with a compelling reason — then annotate @FunctionalInterface
  • Comparator is the star example of a custom functional interface that earns its keep
The core six (43 interfaces reduce to these shapes)
InterfaceSignatureTypical use
Function<T,R>R apply(T t)transform a value — map
Predicate<T>boolean test(T t)filter, match
Consumer<T>void accept(T t)side effects — forEach
Supplier<T>T get()lazy creation, factories
UnaryOperator<T>T apply(T t)same-type transform — replaceAll
BinaryOperator<T>T apply(T a, T b)combine — reduce, merge
Composition builds pipelines without streams
Predicate<String> nonBlank = s -> !s.isBlank();
Predicate<String> shortEnough = s -> s.length() <= 80;
Predicate<String> valid = nonBlank.and(shortEnough);

Function<String, String> clean = String::strip;
Function<String, String> normalize = clean.andThen(String::toLowerCase);
Sources
  • Effective Java (3rd ed.)Items 44, 52
  • Core Java, Volume I: Fundamentals (13th ed.)Ch. 6.2 — Lambda Expressions