Card 06/ 09
Method References, and When a Lambda Is Clearer
String::toUpperCase says the same as s -> s.toUpperCase(), until the body does anything more.
A method reference, written Type::method, is a shorter way to write a lambda whose body only calls one existing method and passes its parameters straight through. The compiler turns it into the same functional interface, an interface with a single abstract method, the lambda would have become.
| Form | Example | The lambda it replaces |
|---|---|---|
| A static method | Integer::parseInt | s -> Integer.parseInt(s) |
| A method on a particular object | System.out::println | s -> System.out.println(s) |
| A method on whichever object arrives | String::toUpperCase | s -> s.toUpperCase() |
| A constructor | ArrayList::new | () -> new ArrayList<>() |
The third row is the one that reads oddly at first. String::toUpperCase takes no argument in the source and produces a Function<String, String>: the parameter becomes the object the method is called on.
The other three rows read the way they look: the arguments are passed to a static method, to a method on an object you already hold, or to a constructor. In every case the compiler matches the referenced method against the one abstract method of the interface it is expecting.
You cannot use one where the body does anything other than pass its parameters straight through: reordering them, adding a constant, negating the result, or calling two things.
names.stream().map(String::toUpperCase) // fine
names.stream().map(s -> s.toUpperCase().trim()) // two calls, so a lambda
names.stream().filter(s -> !s.isBlank()) // negated, so a lambdaUse a method reference when it fits and do not contort a lambda to make one fit. s -> !s.isBlank() is clearer than any arrangement that avoids it.
← → move through sections and cards