The Java Language Specification kind of comments on this in section 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 of Pair<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.
For constructor calls, there are three variations:
Specifying the generic type explicitly |
Inferring the generic type |
Raw Type |
new Something<T>() |
new Something<>() |
new Something() |
But if you refer to a constructor with a method reference, there are only two ways:
Specifying the generic type explicitly |
Inferring the generic type |
Raw Type |
Something<T>::new |
Something::new |
You can't! |
Notice how new Something<>()
(with the diamond) "corresponds" to Something::new
(without the diamond).
Also note you shouldn't use raw types anyway, so the ideal scenario would have been:
Specifying the generic type explicitly |
Inferring the generic type |
Raw Type |
new Something<T>() |
new Something() |
You can't |
Something<T>::new |
Something::new |
You can't! |
Ideally, there would not be any raw types at all as they are not safe. but for historical reasons.
Initially there were no generic types at all. Then they decided to make some of the existing types (e.g Vector
) generic (rather than only adding new types that are generic). And they also wanted to add type inference, so that you don’t have to specify the generic parameter when you call the constructor. Note that at this point, there are still a lot of old code that says new Vector()
.
If new Vector()
were the syntax to infer generic types, a lot of old code would break, for a lot of reasons: there might not be enough context to infer the generic type, for example, because the code weren’t written with genetics in mind! They didn’t want old code to break, so they introduced a new syntax for inferring generic types - the <>.
After a few years, they were introducing method references into the language. This time, the syntax Vector::new
to infer types won’t break any old code because no old code ever used method references! Unlike calling constructors, method references themselves are new!