深入分析者的特点

为了试图深入理解javastream和分割器,我有一些关于分割器特性的细微问题:

Q1: Stream.empty() vs Stream.of() (Stream.of()没有参数)

  • Stream.empty()已经过时,已经大小
  • Stream.of() :已预订, 不可预约 ,已预订,已预订

为什么Stream.empty()没有Stream.empty()的相同特征? 请注意,它与Stream.concat()(特别是没有ORDERED )一起使用时会产生影响。 我会说, Stream.empty()应该不只是IMMUTABLE和ORDERED,但也DISTINCT和NONNULL 。 也有道理Stream.of()只有一个参数有DISTICT

Q2: LongStream.of()没有NONNULL

只注意到NONNULL在LongStream.of不可用。 是不是NONNULL是所有LongStreamIntStreamDoubleStream的主要特征?

Q3: LongStream.range(,)LongStream.range(,).boxed()

  • LongRange.range(,) :已预订, 不可更改,不可空,已大小,已sorting,已sorting,已排除
  • LongStream.range(,).boxed()已订购,已订购,已订购

为什么.boxed()失去了所有这些特征? 它不应该失去任何。

我知道.mapToObj()可能会失去NONNULL,IMMUTABLE和DISTICT ,但.boxed() …没有任何意义。

Q4: .peek()失去IMMUTABLE和NONNULL

LongStream.of(1)SUBSIZED,IMMUTABLE,NONNULL,SIZED,… LongStream.of(1).peek()SUBSIZED,SIZED,…

为什么.peek()失去了这些特征? .peek不应该真的失去任何。

Q5: .skip() .limit()失去了SUBSIZED,IMMUTABLE,NONNULL,SIZED

只要注意,这些操作失去了SUBSIZED,IMMUTABLE,NONNULL,SIZED 。 为什么? 如果尺寸可用,那么计算最终尺寸也很容易。

Q6: .filter()失去IMMUTABLE,NONNULL

只要注意,这个操作也会丢失,并且是不可预测的,不可修改的,不会缩小的 。 失去SUBSIZED和SIZED是有道理的,但其他两个没有意义。 为什么?


如果有人深入了解分裂者,我会很感激。 谢谢。

我不得不承认,当我第一次试图找出这些特性的实际意义,并且感觉到它们在Java 8的实现阶段没有明确解决并且因此而不一致地使用时,我也遇到了困难。

考虑Spliterator.IMMUTABLE

特征值,表示元素来源不能在结构上修改; 也就是说,元素不能被添加,replace或删除,所以在遍历期间不能发生这样的变化。

在这个列表中看到“被replace”是很奇怪的,当谈到一个List或者一个数组时,通常不会被认为是一个结构修改,因此,接受一个数组(不被克隆)的数据stream和分割器工厂会报告IMMUTABLE ,比如LongStream.of(…)Arrays.spliterator(long[])

如果我们更慷慨地把这个解释为“只要客户不能观察到”,那么与CONCURRENT没有什么明显的区别,因为在这两种情况下,都会向客户报告一些内容,而没有任何方式来识别它们是在遍历期间添加的还是是否有人因为搬迁而没有报到,因为没有办法倒回分裂者并进行比较。

规范继续:

不报告IMMUTABLECONCURRENT IMMUTABLE预期会有一个有关在遍历期间检测到的结构干扰的文档化策略(例如IMMUTABLE ConcurrentModificationException )。

这是唯一相关的事情,报告IMMUTABLECONCURRENT IMMUTABLE器保证不会抛出ConcurrentModificationException 。 当然, CONCURRENT语义上排除了SIZED ,但这对客户端代码没有任何影响。

事实上,这些特性并不适用于Stream API中的任何内容,因此,不一致地使用它们将永远不会被注意到。

这也解释了为什么每个中间操作都具有清除CONCURRENTIMMUTABLENONNULL特性的效果:Stream实现不使用它们,其表示stream状态的内部类不维护它们。


同样的, NONNULL并没有在任何地方使用,所以对某些stream的缺席没有任何效果。 我可以追踪LongStream.of(…)问题到内部使用Arrays.spliterator(long[], int, int) ,它委托给
Spliterators.spliterator​(long[] array, int fromIndex, int toIndex, int additionalCharacteristics)

返回的分割器总是报告SIZEDSUBSIZED的特征。 调用者可以为分割器提供额外的特性来报告。 (例如,如果已知数组不会被进一步修改,则指定IMMUTABLE ;如果数组数据被认为具有遇到次序,则指定ORDERED )。 方法Arrays.spliterator(long[], int, int)通常可以用来代替,它返回一个报告SIZEDSUBSIZEDIMMUTABLESUBSIZED IMMUTABLE

再次注意IMMUTABLE特征的不一致使用。 它再次被视为必须保证没有任何修改,而同时, Arrays.spliterator ,反过来Arrays.streamLongStream.of(…)将报告IMMUTABLE特性,即使通过规范,而不能保证调用者不会修改他们的数组。 除非我们考虑设置一个元素不是一个结构修改,但是,然后,整个区别再次变得无意义,因为数组不能在结构上进行修改。

它明确指出没有NONNULL特征。 虽然原始值不能为null ,并且Spliterator.Abstract<Primitive>Spliterator类总是注入一个NONNULL特性,但由Spliterators.spliterator​(long[],int,int,int)返回的Spliterators.spliterator​(long[],int,int,int)器不会inheritanceSpliterator.AbstractLongSpliterator

不好的一面是,这个不能修改规格就不能修正,好处是没有任何后果。


因此,如果我们忽略与CONCURRENTIMMUTABLENONNULL任何问题,

SIZEDskiplimit 。 这是一个众所周知的问题,streamAPI的方式skiplimit结果。 其他的实现是可以想象的。 这也适用于无限stream与limit的组合,其应该具有可预测的大小,但是鉴于当前的实施,还没有。

Stream.concat(…)Stream.empty()结合使用。 这听起来是合理的,一个空的stream不会对结果顺序施加约束。 但是Stream.concat(…)在只有一个input没有顺序时释放顺序的行为是值得怀疑的。 请注意,关于sorting过于激进并不是什么新鲜事,请参阅关于首先被认为是故意的行为的Q&A ,但是随后在Java 8更新60的时候被修复。也许, Stream.concat应该在Stream.concat进行了讨论的时间太…

.boxed()的行为很容易解释。 当它像.mapToObj(Long::valueOf)这样天真地执行时,它将简单地mapToObj所有的知识,因为mapToObj不能假定结果仍然是sorting的或不同的。 但是Java 9已经解决了这个问题。其中, LongStream.range(0,10).boxed()具有SUBSIZED|SIZED|ORDERED|SORTED|DISTINCT特性,保持与实现相关的所有特性。