为什么 `Stream.collect` 是类型安全的,而 `Stream.toArray(IntFunction<A[]>)` 不是?

2022-01-22 00:00:00 types java-8 java java-stream

考虑以下代码片段

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);

为什么 Java 可以在 collect-case 中保证正确的类型(将 collect 的泛型类型更改为例如 Double 会导致编译时错误),但不能在 array case 中保证正确的类型(编译正常,尽管 apply(int) of Double[]::new 给出一个 Double[],而不是 Object[],而是抛出 ArrayStoreException 如果如上使用不正确)?

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)?

如果我更改流的类型而不更改 toArray 调用中给定的 IntFunction,那么生成编译时错误的最佳方法是什么?p>

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?

推荐答案

方法 Stream::toArray 的签名如下所示.请注意类型参数TA是完全不相关的.

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);
}

在ReferencePipeline.java,可以找到如下注释:

In the source of ReferencePipeline.java, you can find the following comment:

由于 AU 没有关系(不可能声明 AU)不会有静态类型检查.因此使用原始类型并假设 A == U 而不是传播 AU 的分离在整个代码库中.U 的运行时类型永远不会检查与 A[] 运行时类型的组件类型是否相等.当元素存储在 A[] 中时将执行运行时检查,因此如果 A 不是U 的超类型会抛出 ArrayStoreException.

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.

相关文章