Saturday, 10 March 2018

Item 43: Prefer method references to lambdas

The primary advantage of lambdas over anonymous classes is that they are more succinct. Java provides a way to generate function objects even more succinct than lambdas: method references. Here is a code snippet from a program that maintains a map from arbitrary keys to Integervalues. If the value is interpreted as a count of the number of instances of the key, then the program is a multiset implementation. The function of the code snippet is to associate the number 1 with the key if it is not in the map and to increment the associated value if the key is already present:


map.merge(key, 1, (count, incr) -> count + incr);


Note that this code uses the merge method, which was added to the Map interface in Java 8. 
The code reads nicely, but there’s still some boilerplate. The parameters count and incrdon’t add much value, and they take up a fair amount of space.


map.merge(key, 1, Integer::sum);
service.execute(GoshThisClassNameIsHumongous::action);service.execute(() -> action());


If you’re programming with an IDE, it will offer to replace a lambda with a method reference wherever it can. You should usually, but not always, take the IDE up on the offer. Occasionally, a lambda will be more succinct than a method reference.

Along similar lines, the Function interface provides a generic static factory method to return the identity function, Function.identity(). It’s typically shorter and cleaner not to use this method but to code the equivalent lambda inline: x -> x.

Many method references refer to static methods, but there are four kinds that do not. Two of them are bound and unbound instance method references. In bound references, the receiving object is specified in the method reference. Bound references are similar in nature to static references: the function object takes the same arguments as the referenced method. In unbound references, the receiving object is specified when the function object is applied, via an additional parameter before the method’s declared parameters. Unbound references are often used as mapping and filter functions in stream pipelines (Item 45). Finally, there are two kinds of constructor references, for classes and arrays. Constructor references serve as factory objects. All five kinds of method references are summarized in the table below:


Method Ref Type
Example
Lambda Equivalent
Static
Integer::parseInt
str -> Integer.parseInt(str)
Bound
Instant.now()::isAfter
Instant then = Instant.now();t -> then.isAfter(t)
Unbound
String::toLowerCase
str -> str.toLowerCase()
Class Constructor
TreeMap<K,V>::new
() -> new TreeMap<K,V>
Array Constructor
int[]::new
len -> new int[len]


In summary, method references often provide a more succinct alternative to lambdas. Where method references are shorter and clearer, use them; where they aren’t, stick with lambdas.

No comments:

Post a Comment