了解下游减少实施 [英] Understanding downstream reduction implementation

查看:144
本文介绍了了解下游减少实施的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试了解JDK下游缩减的实现。这是:

I'm trying to understand the implementation of downstream reduction in JDK. Here is it:

   public static <T, K, D, A, M extends Map<K, D>>
    Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
                                  Supplier<M> mapFactory,
                                  Collector<? super T, A, D> downstream) {
        Supplier<A> downstreamSupplier = downstream.supplier();
        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
        BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {
            K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
            A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
            downstreamAccumulator.accept(container, t);
        };
        BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner());
        @SuppressWarnings("unchecked")
        Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory;

        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
            return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID);
        }
        else {
            @SuppressWarnings("unchecked")
            Function<A, A> downstreamFinisher = 
                       (Function<A, A>) downstream.finisher();  //1, <------------- HERE
            Function<Map<K, A>, M> finisher = intermediate -> {
                intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
                @SuppressWarnings("unchecked")
                M castResult = (M) intermediate;
                return castResult;
            };
            return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
        }
    }

// 1 downstreamFinisher 的类型为功能< A,D> 。判断类型参数声明< T,K,D,A,M扩展Map< K,D>> ,类型 D 不依赖于 A 。那么为什么我们将它转​​换为功能< A,A> 。我认为,类型 D 甚至可能不是 A 的子类。

At //1, the downstreamFinisher is of type Function<A, D>. Judging by the type parameters declarations <T, K, D, A, M extends Map<K, D>>, the type D does not depend on A. So why do we cast it to Function<A, A>. I think, the type D may not even be a subclass of A.

我错过了什么?

推荐答案

这个收藏家实际上违反了<$ c的通用类型安全性$ c> Map ,如果下游收集器没有身份修整器,并且修整器功能返回的类型不同于中间容器类型。

This collector is actually violating the generic type safety of the Map, if the downstream collector doesn’t have an identity finisher and the finisher function returns a different type than the intermediate container type.

在收集操作期间,地图将保存 A 类型的对象,即中间容器类型。然后,在操作结束时, groupingBy 的修整器将遍历地图并将修整器功能应用于每个值并将其替换为最终结果。

During the collect operation, the map will hold objects of type A, i.e. the intermediate container type. Then, at the end of the operation, groupingBy’s finisher will go through the map and apply the finisher function to each value and replace it with the final result.

当然,如果没有未经检查的操作,这将无法实现。有多种方法,您发布的变体,将地图供应商的类型从供应商< M> 更改为供应商< Map< K,A>> (第一个未经检查的操作),因此编译器接受地图将保存 A 类型的值,而不是 d 。这就是终结者功能必须更改为功能< A,A> (第二次未经检查的操作)的原因,所以它可以在地图的 replaceAll 操作中使用,该操作似乎需要 A 类型的对象,尽管它实际上是 d 。最后,必须将结果映射转换为 M (第三个未经检查的操作)以获取预期结果类型 M ,供应商实际提供的。

Of course, this can’t be implemented without unchecked operations. There are multiple ways to do it, the variant you have posted, changes the type of the map supplier from Supplier<M> to Supplier<Map<K, A>> (the first unchecked operation), so the compiler accepts that the map will hold values of type A rather than D. That’s why the finisher function must be changed to Function<A,A> (the second unchecked operation), so it can be used in the map’s replaceAll operation which appears to require objects of type A despite it’s actually D. Finally, the result map must be cast to M (the third unchecked operation) to get an object of the expected result type M, which the supplier actually supplied.

正确的类型安全替代方案是使用不同的地图并通过填充转换结果填充结果图来执行修整操作中间地图的值。这不仅可能是昂贵的操作,还需要第二个供应商用于中间地图,因为所提供的供应商仅生成适合最终结果的地图。显然,开发人员认为这是一种可接受的类型安全漏洞。

The correct type safe alternative would be to use different maps and perform the finishing operation by populating the result map with the result of converting the values of the intermediate map. Not only might this be an expensive operation, it would require a second supplier for the intermediate map, as the provided supplier only produces maps suitable for the final result. So apparently, the developers decided this to be an acceptable breach of the type safety.

请注意,当您尝试使用<$ c时,您会发现不安全的操作$ c> Map 强制执行类型安全的实现:

Note that you can notice the unsafe operation, when you try to use a Map implementation which enforces type safety:

Stream.of("foo", "bar").collect(Collectors.groupingBy(String::length,
    () -> Collections.checkedMap(new HashMap<>(), Integer.class, Long.class),
    Collectors.counting()));

将使用此实现生成 ClassCastException ,因为它试图将一个中间容器(一个数组)而不是 Long 放入Map中。

will produce a ClassCastException with this implementation because it tries to put an intermediate container (an array) instead of the Long into the Map.

这篇关于了解下游减少实施的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆