流的管道如何在像IntPipeline这样的java中工作

Joh*_*ler 2 java java-8 java-stream

我正在学习java 8流,有些问题对我而言.

假设这段代码:

 new Random().ints().forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

它在某种程度上内部称IntPipeline,我认为有责任无限期地生成这些内容.通过查看java源代码很难理解Streams实现.

您能否给出一个简短的解释,或者给出一些关于如何生成流以及如何连接管道操作的好/易理解的材料.整数上面的代码示例是随机生成的,如何建立这种连接?

Tag*_*eev 5

Stream实现分为Spliterator(输入特定代码)和管道(与输入无关的代码).在Spliterator类似Iterator.主要区别如下:

  • 它可以将自己分成两部分(trySplit方法).对于有序的分裂器,部件是前缀和后缀(例如,对于阵列,它可以是前半部分和后半部分).对于无序源(如随机数),两个部分都可以生成一些元素.由此产生的部分能够进一步分裂(除非它们变得太小).此功能对于并行流处理至关重要.

  • 它可以报告其大小或精确或估计.确切的大小可以用于为某些流操作预分配内存,toArray()或者只是将其返回给调用者(如count()Java-9).估计的大小用于并行流处理以决定何时停止分割.

  • 它可以报告一些特征,如ORDERED,SORTED,DISTINCT等.

  • 它实现了内部迭代:而不是两个方法hasNext,next你有一个方法tryAdvance执行提供的Consumer一次,除非没有更多的元素.

也有原始专业化Spliterator接口(Spliterator.OfInt等),它可以帮助您处理类似的原始值int,longdouble有效.

因此,要创建自己的Stream数据源,必须实现Spliterator,然后调用StreamSupport.stream(mySpliterator, isParallel)以创建StreamStreamSupport.int/long/doubleStream原始特化.所以实际上Random.ints调用StreamSupport.intStream提供自己的分裂器.您不必Stream自己实施所有操作.通常Stream,对于不同的源,在JDK中每个流类型仅实现一次接口.有基本的抽象类AbstractPipeline和四个实现(ReferencePipelinefor Stream,IntPipelinefor IntStream,LongPipelinefor LongStreamDoublePipelinefor DoubleStream).但是,你有更多的来源(Collection.stream(),Arrays.stream(),IntStream.range,String.chars(),BufferedReader.lines(),Files.lines(),Random.ints()等等,甚至更多地出现在Java-9中.所有这些来源都是使用自定义分裂器实现的.实现它Spliterator比实现整个流管道(特别是考虑到并行处理)要简单得多,因此这种分离是有意义的.

如果要创建自己的流源,可以开始扩展AbstractSpliterator.在这种情况下,您只需要实现tryAdvance并调用超类构造函数,以提供估计的大小和一些特征.在AbstractSpliterator通过读取源的一部分进入阵列(调用你的实现提供了默认的分裂行为tryAdvance方式)和创建这个前缀基于阵列的spliterator.当然,这种策略性能不是很高,而且往往只提供有限的并行性,但作为一个起点,它是可以的.稍后您可以trySplit自己实施提供更好的拆分策略.