Consider the following code fragment
String strings[] = {"test"};
final List<String> collect = java.util.Arrays.stream(strings).collect(java.util.stream.Collectors.toList());
final Double[] array = java.util.Arrays.stream(strings).toArray(Double[]::new);
Why can Java guarantee the correct type in the collect-case (changing the generic type of collect to e.g. Double leads to a compile time error), but not in the array case (compiles fine, despite apply(int)
of Double[]::new
gives a Double[]
, not an Object[]
, but throws ArrayStoreException
if used incorrectly as above)?
What would be the best way to generate a compile time error in case I change the type of the stream without changing the given IntFunction
in the toArray
call?
The signature of the method Stream::toArray
looks as follows. Please note that the type parameters T
and A
are completely unrelated.
public interface Stream<T> {
<A> A[] toArray(IntFunction<A[]> generator);
}
In the source of ReferencePipeline.java, you can find the following comment:
Since A
has no relation to U
(not possible to declare that A
is an upper bound of U
)
there will be no static type checking.
Therefore use a raw type and assume A == U
rather than propagating the separation of A
and U
throughout the code-base.
The runtime type of U
is never checked for equality with the component type of the runtime type of A[]
.
Runtime checking will be performed when an element is stored in A[]
, thus if A
is not a
super type of U
an ArrayStoreException
will be thrown.