流分离器实现细节

Eug*_*ene 6 java java-8 java-stream

在查看的源代码时WrappingSpliterator::trySplit,我对其实现很误解:

    @Override
    public Spliterator<P_OUT> trySplit() {
        if (isParallel && buffer == null && !finished) {
            init();

            Spliterator<P_IN> split = spliterator.trySplit();
            return (split == null) ? null : wrap(split);
        }
        else
            return null;
    }
Run Code Online (Sandbox Code Playgroud)

如果您想知道这为什么重要,是因为例如:

Arrays.asList(1,2,3,4,5)
      .stream()
      .filter(x -> x != 1)
      .spliterator();
Run Code Online (Sandbox Code Playgroud)

正在使用它。以我的理解,在流中添加任何中间操作都将导致该代码被触发。

基本上,此方法表示除非流是并行的,否则将此Spliterator视为根本无法拆分的分离器。这对我很重要。在我的一种方法中(这就是我获得该代码的方式),我获得了a Stream作为输入,并使用手动将其“解析”成小块trySplit。你能想到的,例如,我试图做一个findLastStream

这就是我切成小块的愿望,因为我一这样做:

Spliterator<T> sp = stream.spliterator();
Spliterator<T> prefixSplit = sp.trySplit();
Run Code Online (Sandbox Code Playgroud)

我发现,prefixSplitnull的,这意味着我根本无法做任何事情比其他消耗整个spforEachRemaning

这有点不可思议,也许对于何时filter存在有意义。因为在这种情况下(据我所知)唯一Spliterator可以返回的方法是使用某种a buffer,甚至可能具有预定义的大小(很像Files::lines)。但是为什么这样:

Arrays.asList(1,2,3,4)
      .stream()
      .sorted()
      .spliterator()
      .trySplit();
Run Code Online (Sandbox Code Playgroud)

回报null是我不明白的事情。sorted是一种有状态操作,无论如何都将缓冲元素,而实际上没有减少或增加它们的初始数量,因此至少在理论上,这可以返回除null... 以外的其他值。

Hol*_*ger 1

当您调用spliterator()a时Stream,当前实现只有两种可能的结果。

\n\n

如果流没有中间操作,您\xe2\x80\x99将获得用于构造流的源分裂器,其分裂能力完全独立于流\xe2\x80\x99的并行状态,事实上, spliterator 不知道有关流的任何信息。

\n\n

否则,您\xe2\x80\x99将得到一个WrappingSpliterator,它将封装源Spliterator和管道状态,表示为PipelineHelperSpliterator和 的这种组合PipelineHelper不需要并行工作,事实上,在 的情况下也不起作用distinct(),因为 和 的WrappingSpliterator组合将得到完全不同的组合,具体取决于 Stream 是否并行。

\n\n

对于无状态中间操作,这不会产生任何影响。但是,正如 \xe2\x80\x9c 中所讨论的,为什么stream.spliterator() 的 tryAdvance 可能会将项目累积到缓冲区中?\xe2\x80\x9d,WrappingSpliterator是一个\xe2\x80\x9cone-fits-all实现\xe2\x80\x9d,它不\xe2\x80\x99考虑管道的实际性质,因此它的局限性是所有支持的管道阶段的所有可能的限制。因此,存在一种在忽略该parallel标志时无法\xe2\x80\x99 工作的场景,足以禁止在不存在时对所有管道进行拆分parallel

\n