我正在阅读Effective Java 3并注意到第43项中的这段代码:“首选方法引用lambdas”:
TreeMap<K,V>::new
注意类型参数。我一直都这么做:
TreeMap::new
我使用Intellij并且从未收到有关此更改或任何更改建议的警告。实际上,当我让IDE将上面的方法引用更改为lambda时,它会将其转换为
() -> new TreeMap<Integer, Integer>()
包含类型参数的价值是多少?编译器不能根据变量的类型参数推断它吗?根据IDE如何将方法引用转换为lambda,它似乎可以。
答案 0 :(得分:4)
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
.