Functional Programming & Streams

Method References

A method reference names an existing method where a lambda is expected: String::length, System.out::println, User::new. When it's clearer than the lambda, use it; when it isn't, don't.
  • Five kinds: static, bound instance, unbound instance, constructor, array constructor
  • ClassName::instanceMethod — the first lambda argument becomes the receiver
  • expr::instanceMethod captures the receiver now, calls later
  • Prefer method references when shorter and clearer (EJ 43)
The five kinds
KindSyntaxEquivalent lambda
StaticInteger::parseInts -> Integer.parseInt(s)
Bound (receiver fixed)System.out::printlnx -> System.out.println(x)
Unbound (receiver = 1st arg)String::toLowerCases -> s.toLowerCase()
ConstructorArrayList::new() -> new ArrayList<>()
Array constructorString[]::newn -> new String[n]

The unbound form is the one worth internalizing: in Comparator.comparing(Person::getName), each Person flowing through becomes the receiver of getName. With two parameters, String::compareToIgnoreCase means (a, b) -> a.compareToIgnoreCase(b).

Where they shine
people.stream()
      .map(Person::getName)                       // unbound
      .filter(Objects::nonNull)                    // static
      .sorted(String::compareToIgnoreCase)         // unbound, 2-arg
      .forEach(System.out::println);               // bound

List<Set<String>> groups = names.stream()
      .collect(groupingBy(String::length, mapping(s -> s, toCollection(TreeSet::new))));
Sources
  • Core Java, Volume I: Fundamentals (13th ed.)Ch. 6.2.4 — Method References
  • Effective Java (3rd ed.)Item 43