为了尝试深入理解java流和分割器,我对有一些微妙的问题。分流器特性 :
Q1:Stream.empty()
对比 Stream.of()
(Stream.of() 不带参数)
Stream.empty()
: 超大尺寸 Stream.of()
:缩小,不可变 , 尺寸, 已订购 为什么
Stream.empty()
不具有与 Stream.of()
相同的特征?请注意,它在与 Stream.concat() 结合使用时会产生影响(特别是没有 ORDERED
)。我会说 Stream.empty()
不仅应该具有 IMMUTABLE 和 ORDERED,还应该具有 DISTINCT 和 NONNULL。也有道理 Stream.of()
只有一个参数具有 DISTICT。Q2:
LongStream.of()
没有 NONNULL 刚刚注意到 NONNULL 在
LongStream.of
中不可用.不是
NONNULL
所有LongStream
的主要特征s, IntStream
s 和 DoubleStream
?Q3:
LongStream.range(,)
对比 LongStream.range(,).boxed()
LongRange.range(,)
:缩小,不可变,非空 , 尺码, 订购, 排序,不同 LongStream.range(,).boxed()
: 超大尺寸、已定尺寸、已订购 为什么
.boxed()
失去所有这些特征?它不应该失去任何东西。我明白
.mapToObj()
可能会丢失 NONNULL、IMMUTABLE 和 DISTICT,但是 .boxed()
……没意义。Q4:
.peek()
失去 IMMUTABLE 和 NONNULL LongStream.of(1)
: SUBSIZED, IMMUTABLE, NONNULL, SIZED, ...LongStream.of(1).peek()
: 超大、超大、...为什么
.peek()
失去这些特性? .peek
真的不应该失去任何东西。Q5:
.skip()
, .limit()
丢失 SUBSIZED、IMMUTABLE、NONNULL、SIZED 请注意,这些操作丢失了 SUBSIZED、IMMUTABLE、NONNULL、SIZED。为什么?如果尺寸可用,那么计算最终尺寸也很容易。
Q6:
.filter()
失去 IMMUTABLE, NONNULL 请注意,此操作也会丢失 SUBSIZED、IMMUTABLE、NONNULL、SIZED。丢失 SUBSIZED 和 SIZED 是有意义的,但其他两个没有意义。为什么?
如果有人深入了解拆分器可以带来一些清晰度,我将不胜感激。谢谢。
最佳答案
我不得不承认,当我第一次尝试找出这些特性的实际含义时,我也遇到了困难,并且感觉它们的含义在 Java 8 的实现阶段没有明确确定,因此使用不一致。
考虑 Spliterator.IMMUTABLE
:
Characteristic value signifying that the element source cannot be structurally modified; that is, elements cannot be added, replaced, or removed, so such changes cannot occur during traversal.
在这个列表中看到“替换”很奇怪,在谈到
List
时,这通常不被认为是结构修改。或数组,因此,流和拆分器工厂接受数组(未克隆)报告 IMMUTABLE
, 喜欢 LongStream.of(…)
或 Arrays.spliterator(long[])
.如果我们把这更宽泛地解释为“只要不被客户端观察到”,则与
CONCURRENT
没有显着差异。 ,因为在任何一种情况下,某些元素将被报告给客户端,而无法识别它们是在遍历期间添加的,还是由于删除而未报告的,因为无法倒带拆分器并进行比较。规范继续:
A Spliterator that does not report
IMMUTABLE
orCONCURRENT
is expected to have a documented policy (for example throwingConcurrentModificationException
) concerning structural interference detected during traversal.
这是唯一相关的事情,一个拆分器报告,
IMMUTABLE
或 CONCURRENT
, 保证永远不会抛出 ConcurrentModificationException
.当然,CONCURRENT
排除 SIZED
语义上,但这对客户端代码没有影响。事实上,这些特性并没有用于 Stream API 中的任何东西,因此,不一致地使用它们永远不会在某处引起注意。
这也是为什么每次中间操作都有清除
CONCURRENT
的效果的解释。 , IMMUTABLE
和 NONNULL
特性:Stream 实现不使用它们,其内部表示流状态的类不维护它们。同样,
NONNULL
不在任何地方使用,因此某些流的缺失没有任何影响。我可以找到 LongStream.of(…)
问题归结为 Arrays.spliterator(long[], int, int)
的内部使用委托(delegate)给Spliterators.spliterator(long[] array, int fromIndex, int toIndex, int additionalCharacteristics)
:The returned spliterator always reports the characteristics
SIZED
andSUBSIZED
. The caller may provide additional characteristics for the spliterator to report. (For example, if it is known the array will not be further modified, specifyIMMUTABLE
; if the array data is considered to have an encounter order, specifyORDERED
). The methodArrays.spliterator(long[], int, int)
can often be used instead, which returns a spliterator that reportsSIZED
,SUBSIZED
,IMMUTABLE
, andORDERED
.
注意(再次)
IMMUTABLE
的不一致使用特征。它再次被视为必须保证没有任何修改,同时,Arrays.spliterator
反过来 Arrays.stream
和 LongStream.of(…)
将举报 IMMUTABLE
特性,即使通过规范,也不能保证调用者不会修改他们的数组。除非我们考虑将元素设置为不是结构修改,但是,整个区别再次变得无意义,因为数组不能在结构上修改。并且明确指出没有
NONNULL
特征。虽然很明显原始值不能是 null
,以及 Spliterator.Abstract<Primitive>Spliterator
类总是注入(inject)一个 NONNULL
特征,Spliterators.spliterator(long[],int,int,int)
返回的拆分器不继承自 Spliterator.AbstractLongSpliterator
.不好的是,这不能在不改变规范的情况下解决,好的是,无论如何它没有任何后果。
因此,如果我们忽略
CONCURRENT
的任何问题, IMMUTABLE
, 或 NONNULL
,没有任何后果,我们有SIZED
和 skip
& limit
.这是一个众所周知的问题,结果 skip
和 limit
已由 Stream API 实现。其他实现是可以想象的。这也适用于无限流与 limit
的组合。 ,它应该具有可预测的大小,但考虑到当前的实现,却没有。合并
Stream.concat(…)
与 Stream.empty()
.空流不会对结果顺序施加约束,这听起来很合理。但是Stream.concat(…)
当只有一个输入没有订单时释放订单的行为是值得怀疑的。请注意,在订购方面过于激进并不是什么新鲜事,请参阅 this Q&A关于首先被认为是故意的行为,但后来在 Java 8 更新 60 中被修复。也许,Stream.concat
也应该在这个时候讨论…….boxed()
的行为很容易解释。当它像 .mapToObj(Long::valueOf)
这样天真地实现时,它只会丢失所有知识,如 mapToObj
不能假设结果仍然是排序的或不同的。但这已通过 Java 9 修复。那里,LongStream.range(0,10).boxed()
有 SUBSIZED|SIZED|ORDERED|SORTED|DISTINCT
特性,维护所有与实现相关的特性。
关于java - 深入了解分离器特性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46644595/