I'm reading Effective Java 3 and noticed this code in Item 43: “Prefer method references to lambdas”:
TreeMap<K,V>::new
Notice the type parameters. I've always just done:
TreeMap::new
I use Intellij and have never gotten a warning about this or any recommendation to change it. In fact, when I have the IDE change the above method reference into a lambda it converts it to
() -> new TreeMap<Integer, Integer>()
What is the value in including the type parameters? Can't the compiler infer it based on the type parameters of the variable? Based on how the IDE transformed the method reference into a lambda it seems like it can.
The constructor reference TreeMap::new
is the same as using diamond type inference (§15.13.1):
For convenience, when the name of a generic type is used to refer to an instance method (where the receiver becomes the first parameter), the target type is used to determine the type arguments. This facilitates usage like
Pair::first
in place ofPair<String,Integer>::first
.Similarly, a method reference like
Pair::new
is treated like a "diamond" instance creation(new Pair<>())
. Because the "diamond" is implicit, this form does not instantiate a raw type; in fact, there is no way to express a reference to the constructor of a raw type.
You'd need to provide type arguments explicitly in more or less the same situations as when you would need to provide type arguments to a constructor explicitly.
For example, in the following, the call to get
prevents the return assignment from being considered during inference of supplier
, so T
is inferred to be ArrayList<Object>
:
class Example {
public static void main(String[] args) {
ArrayList<String> list =
supplier(ArrayList::new).get(); // compile error
}
static <T> Supplier<T> supplier(Supplier<T> s) { return s; }
}
In that contrived example, we'd have to use ArrayList<String>::new
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With