0

I have question about using constructor reference using generics. Why does l = ArrayList<>::new; have error?
But if I use lambda expression, l = ()-> new ArrayList<>();, it is okay. Why?

public  static void main(String... args){
        Supplier<ArrayList> 

        l = ()-> new ArrayList();  // good
        l = ()-> new ArrayList<>();     // good
        l = ()-> new ArrayList<Integer>();  // good
        l = ArrayList<Integer>::new;    // good
        l = ArrayList::new;  // good
        l = ArrayList<>::new;  // Error, why?
    }                               
}
ernest_k
  • 44,416
  • 5
  • 53
  • 99
CoolJetdi
  • 35
  • 3

1 Answers1

3

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!

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Hi Sweeper, thanks for the info! According to your above explanation, the table that you mentioned "ideal scenario". Under the "Inferring the generic type", you have new Something() to Something::new. Shouldn't that be new Something<>() to Something::new? – CoolJetdi May 08 '21 at 23:00
  • Therefore, let's say I have Supplier s = Something::new. Something on the left side of assignment is raw type. On the right side, Something::new is equivalent to new Something(). And this "new Something()" is actually inferring the generic type from the left side of the raw type Something. – CoolJetdi May 09 '21 at 00:55
  • @CoolJetdi Is `Something` declared to be generic? If `Something` is not generic, then this is irrelevant to the question. If it is, then yes, `Something` on the left is a raw type, but no, `Something::new` does not correspond to `new Something()` (that would be the ideal situation, where `new Something()` is the syntax to infer the generic type). It corresponds to `new Something<>()`. Also no, the generic type inferred is `Object` (doesn't really matter since LHS is raw type). We are not trying to infer the type parameter of `Supplier`. We are trying to infer the type parameter of `Something`. – Sweeper May 09 '21 at 01:01
  • I see. I got your point. I mistaken your meaning of "ideal situation". Thank you! – CoolJetdi May 09 '21 at 01:32