Your question is justified. In short, the method reference does indeed use the raw type (or should use the raw type) and the reason, why the creation of generic arrays is forbidden, still applies when using method references, hence, being able to silently create a function creating a generic array clearly violates the intention of the language design.
The reason why the creation of generic array is forbidden, is that the array type inheritance, stemming from a pre-Generics era, is incompatible with the generic type system. I.e. you can write:
IntFunction<List<String>[]> af = List[]::new; // should generate warning
List<String>[] array = af.apply(10);
Object[] objArray = array;
objArray[0] = Arrays.asList(42);
List<String> list = array[0]; // heap pollution
At this place, it must be emphasized that contrary to some answers here, the compiler does not perform type inference on the expression List[]::new to deduce the generic element type List<String>. It’s easy to prove that generic array creation still is forbidden:
IntFunction<List<String>[]> af = List<String>[]::new; // does not compile
Since List<String>[]::new is illegal, it would be strange if List[]::new was accepted without a warning, by inferring it to be effectively the illegal List<String>[]::new.
JLS §15.13 clearly states:
If a method reference expression has the form ArrayType :: new, then ArrayType must denote a type that is reifiable (§4.7), or a compile-time error occurs.
This already implies that List<String>[]::new is illegal, because List<String> is not reifiable, whereas List<?>[]::new is legal, as List<?> is reifiable, and List[]::new is legal if we consider List to be a raw type, as the raw type List is reifiable.
Then §15.13.1 states:
If the method reference expression has the form ArrayType :: new, a single notional method is considered. The method has a single parameter of type int, returns the ArrayType, and has no throws clause. If n = 1, this is the only potentially applicable method; otherwise, there are no potentially applicable methods.
In other words, the behavior of the List[]::new expression above is the same as if you had written:
IntFunction<List<String>[]> af = MyClass::create;
…
private static List[] create(int i) {
return new List[i];
}
except that the method create is only notional. And indeed, with this explicit method declaration, there are only raw type warnings at the create method, but no unchecked warnings regarding the conversion of List[] to List<String>[] at the method reference. So it’s understandable, what happens in the compiler in the List[]::new case, where the method using raw types is only notional, i.e. doesn’t exist in source code.
But the absence of unchecked warnings is a clear violation of JLS §5.1.9, Unchecked Conversion:
Let G name a generic type declaration with n type parameters.
There is an unchecked conversion from the raw class or interface type (§4.8) G to any parameterized type of the form G<T₁,...,Tₙ>.
There is an unchecked conversion from the raw array type G[]ᵏ to any array type of the form G<T₁,...,Tₙ>[]ᵏ. (The notation []ᵏ indicates an array type of k dimensions.)
Use of an unchecked conversion causes a compile-time unchecked warning unless all type arguments Tᵢ (1 ≤ i ≤ n) are unbounded wildcards (§4.5.1), or the unchecked warning is suppressed by the SuppressWarnings annotation (§9.6.4.5).
So, a conversion of List[] to List<?>[] is legal, as List is parameterized with an unbounded wildcard, but the conversion from List[] to List<String>[] must produce an unchecked warning, which is crucial here, as the use of List[]::new does not produce the raw type warning that appears with an explicit creation method. The absence of raw type warnings seems not to be a violation (as far as I understood §4.8) and it wouldn’t be a problem, if javac created the required unchecked warning.
n -> new Test[n];instead ofTest[]::new(which should basically be the same) will again give you an unchecked compile warning – Roland 20 hours agon -> new Test[n]does produce warnings. But the desugared form isn’t sufficient to derive a rule. E.g., the implementation ofFunction.identity()ist -> t, which allows to get a singletonFunctioninstance at runtime, whereas any other (non-lambda) code that would produce the same desugared (singleton) code, would produce an unchecked warning, due to different rules. In this case, the rules forn -> new Test[n]andTest[]::newalso are different, still, I gathered the relevant parts forArrayType::new. I also added an emphasis to the conclusion as you suggested. – Holger 16 hours ago