java - 为什么 Collectors.toUnmodifiableList 使用中间累加器的类型检查?

标签 java java-stream collectors

我看到以下代码(JDK 16、JDK 17):

    public static <T>
    Collector<T, ?, List<T>> toUnmodifiableList() {
        return new CollectorImpl<>(ArrayList::new, List::add,
                                   (left, right) -> { left.addAll(right); return left; },
                                   list -> {
                                       if (list.getClass() == ArrayList.class) { // ensure it's trusted
                                           return SharedSecrets.getJavaUtilCollectionAccess()
                                                               .listFromTrustedArray(list.toArray());
                                       } else {
                                           throw new IllegalArgumentException();
                                       }
                                   },
                                   CH_NOID);
    }

使用 if (list.getClass() == ArrayList.class) { 检查有什么意义?为什么不简单地使这段代码像

return new CollectorImpl<>(ArrayList::new, ArrayList::add,                                          
                           (left, right) -> { left.addAll(right); return left; },              
                           list -> SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(list.toArray()),                                                                  
                           CH_NOID);                                                           

通过将 List::add 替换为 ArrayList::add,我们提供了类的最具体的方法句柄,而不是接口(interface)。 最后一段代码假设累加器实例将作为 ArrayList 实例传递给“accumulator”、“combiner”和“finisher”参数(实际上,它会,因为 CollectorImpl 对所有实例使用相同的不变通用变量 A参数)。我看不出 IllegalArgumentException 和 ClassCastException 之间有什么区别,除了代码的复杂性和在终结器中的额外检查。

最佳答案

变化来自

Collector<T, ?, List<T>> toUnmodifiableList() {
    return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                               (left, right) -> { left.addAll(right); return left; },
                               list -> (List<T>)List.of(list.toArray()),
                               CH_NOID);
}

public static <T>
Collector<T, ?, List<T>> toUnmodifiableList() {
    return new CollectorImpl<>(ArrayList::new, List::add,
                               (left, right) -> { left.addAll(right); return left; },
                               list -> {
                                   if (list.getClass() == ArrayList.class) { // ensure it's trusted
                                       return SharedSecrets.getJavaUtilCollectionAccess()
                                                           .listFromTrustedArray(list.toArray());
                                   } else {
                                       throw new IllegalArgumentException();
                                   }
                               },
                               CH_NOID);
}

分两步发生。中间的步骤是

Collector<T, ?, List<T>> toUnmodifiableList() {
    return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                               (left, right) -> { left.addAll(right); return left; },
                               list -> (List<T>)SharedSecrets.getJavaUtilCollectionAccess()
                                                             .listFromTrustedArray(list.toArray()),
                               CH_NOID);
}

第一步是出于性能原因引入的(https://bugs.openjdk.java.net/browse/JDK-8156071),后来有人注意到这会导致安全问题(https://bugs.openjdk.java.net/browse/JDK-8254090https://github.com/openjdk/jdk/pull/449#issuecomment-704001706),因此进行了第二步更改。

关于java - 为什么 Collectors.toUnmodifiableList 使用中间累加器的类型检查?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68971402/

相关文章:

java - 如何在不收集或检查一个流的所有元素是否存在于另一流中的情况下比较两个 Int Streams?

java - map 流到 map

Java 8 收集器 API

Java 8 Streams : why does Collectors. toMap 对于带有通配符的泛型表现不同?

java - 按键将对象列表分组到具有唯一对象子列表的列表中(使用java流)

java - ActiveMQ 消息出队但未使用

java - AOSP 方法名称结尾

java - 如何让spring使用mysql而不是hsql

java - 如何将实体管理器查询中的非类型化列表转换为类型化列表?

java 8 带有泛型的流收集器