Why is `Stream.collect` type-safe and `Stream.toArray(IntFunction<A[]>)` is not?
java, java-8, java-stream, types
Solution
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.
Problem
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?