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
Note that this code uses the
The code reads nicely, but there’s still some boilerplate. The parameters
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
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:
Integer
values. 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 incr
don’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