【问题标题】:Why is `Stream.collect` type-safe and `Stream.toArray(IntFunction<A[]>)` is not?为什么 `Stream.collect` 是类型安全的,而 `Stream.toArray(IntFunction<A[]>)` 不是?
【发布时间】:2019-01-23 11:40:41
【问题描述】:

考虑以下代码片段

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 中保证正确的类型(编译正常,尽管 @987654323 的 apply(int) @ 给出一个Double[],而不是一个Object[],但是如果如上所述使用不正确,则会抛出ArrayStoreException)?

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

【问题讨论】:

    标签: java types java-8 java-stream


    【解决方案1】:

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

    public interface Stream<T> {
        <A> A[] toArray(IntFunction<A[]> generator);
    }
    

    ReferencePipeline.java的源码中,可以找到如下评论:

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

    【讨论】:

    • 这是A super T 会提供帮助的情况之一吗?如果是这样,那么他们没有为此修复它是非常有趣的,因为如果它在这样的 API 中对我来说似乎是“必须的”。
    • 好吧,正如您所指出的,我正在寻找它们完全不相关的原因。设置&lt;A super T&gt; 似乎很容易。因此,我预计 Stream 接口或类似的实现中会出现一些问题。
    • @muued 请注意&lt;A super T&gt; 在语法上在类型声明中是不可能的。您只能将? super T 作为类型,但不能捕获?。这与可以捕获? extends TX extends T 不同。在创建泛型时它被 Java 省略了,因为它被认为不够有用
    • @skiwi 啊,这完美地解释了它,谢谢。因此,您提到的缺失 super 以及无法通过泛型类型区分方法以阻止它们添加 T[] toArray(IntFunction&lt;T[]&gt; generator); 的事实导致了我们现在的痛苦
    • @skiwi 这个问题并不是 Stream API 独有的。 Collection.toArray(T[]) 是一个同样有效的用例,所以如果这不足以支持super,那么没有理由这样做。
    猜你喜欢
    • 1970-01-01
    • 2013-07-31
    • 2010-09-20
    • 2011-01-09
    • 2014-07-24
    • 2011-01-27
    • 1970-01-01
    相关资源
    最近更新 更多