首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么迭代映射的排序流会计算更多不必要的元素?

为什么迭代映射的排序流会计算更多不必要的元素?
EN

Stack Overflow用户
提问于 2019-11-21 02:04:43
回答 1查看 123关注 0票数 8

考虑这个小程序,我们获取一个流,对其进行排序,映射,然后迭代:

代码语言:javascript
复制
public class AlphabetOrdinals {

    private static final List<Character> ALPHABET = List.of('a', 'b', 'c', 'd', 'e', 'f');
    private static final int STOP_ORDINAL = 'b' - 'a';

    public static void main(String[] args) {
        System.out.println("java.runtime.version = " + System.getProperty("java.runtime.version"));

        Stream<Integer> ordinals = ALPHABET.stream()
                                           .sorted()
                                           .map(AlphabetOrdinals::ordinal);

        int count = 0;

        Iterator<Integer> iterator = ordinals.iterator();
        while (iterator.hasNext()) {
            int ordinal = iterator.next();
            if (ordinal > STOP_ORDINAL) {
                System.out.println("stopping at " + ordinal);
                break;
            }
            System.out.println("consuming " + ordinal);
            ++count;
        }

        System.out.println("consumed " + count + " ordinals");
    }

    private static int ordinal(char letter) {
        int ordinal = letter - 'a';
        System.out.println("performing EXTREMELY EXPENSIVE mapping of " + letter + " -> " + ordinal);
        return ordinal;
    }

}

这个程序很愚蠢,但它是从一个真实的程序简化而来的,在这个程序中,迭代与另一个流上的迭代交织在一起,所以我不能很容易地将它替换为takeWhile/forEach。

我希望这个程序打印:

代码语言:javascript
复制
java.runtime.version = 11+28
performing EXTREMELY EXPENSIVE mapping of a -> 0
consuming 0
performing EXTREMELY EXPENSIVE mapping of b -> 1
consuming 1
performing EXTREMELY EXPENSIVE mapping of c -> 2
stopping at 2
consumed 2 ordinals

但它会打印:

代码语言:javascript
复制
java.runtime.version = 11+28
performing EXTREMELY EXPENSIVE mapping of a -> 0
performing EXTREMELY EXPENSIVE mapping of b -> 1
performing EXTREMELY EXPENSIVE mapping of c -> 2
performing EXTREMELY EXPENSIVE mapping of d -> 3
performing EXTREMELY EXPENSIVE mapping of e -> 4
performing EXTREMELY EXPENSIVE mapping of f -> 5
consuming 0
consuming 1
stopping at 2
consumed 2 ordinals

如果我删除.sorted(),它会打印出我所期望的内容。

这一切为什么要发生?

在实际的程序中,映射步骤涉及从速度较慢的网络驱动器读取大量数据,因此我不希望在绝对必要的情况下多次执行此操作!

EN

回答 1

Stack Overflow用户

发布于 2019-11-21 02:32:04

无聊的答案:

这就是streams API实现的编写方式。

不那么无聊的答案:

流具有某种类型的操作链,以应用于输入。对于引用流,添加的排序操作是:java.util.stream.SortedOps.RefSortingSink (假设您有一个与我类似的JDK )。对于map,它是:

代码语言:javascript
复制
new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
            @Override
            Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
                return new Sink.ChainedReference<P_OUT, R>(sink) {
                    @Override
                    public void accept(P_OUT u) {
                        downstream.accept(mapper.apply(u));
                    }
                };
            }
        };

java.util.stream.SortedOps.RefSortingSink实现的相关部分如下:

代码语言:javascript
复制
  @Override
        public void begin(long size) {
            if (size >= Nodes.MAX_ARRAY_SIZE)
                throw new IllegalArgumentException(Nodes.BAD_SIZE);
            list = (size >= 0) ? new ArrayList<T>((int) size) : new ArrayList<T>();
        }

        @Override
        public void end() {
            list.sort(comparator);
            downstream.begin(list.size());
            if (!cancellationWasRequested) {
                list.forEach(downstream::accept);
            }
            else {
                for (T t : list) {
                    if (downstream.cancellationRequested()) break;
                    downstream.accept(t);
                }
            }
            downstream.end();
            list = null;
        }

        @Override
        public void accept(T t) {
            list.add(t);
        }

正如您所看到的,排序将整个列表传递给链中的下一个操作(下一个操作称为downstream)。然而,map操作接收它接收到的任何内容,使用映射函数并将其传递给下游。这意味着如果你只使用map,你会得到懒惰的预期行为,而如果你使用排序,整个现在排序的流在list.forEach(downstream::accept)中被塞进map的喉管,map不能拒绝接受它,或者只接受它的一部分。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58960735

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档