当前位置: 首页 > 知识库问答 >
问题:

深入了解spliterator的特性

龙承德
2023-03-14

为了试图深入理解Java流和spliterator,我有一些关于spliterator特性的微妙问题:

Q1:stream.empty()stream.of()(不带参数的stream.of())

  • stream.empty():已沉降,大小
  • stream.of():沉降的、不可变的、有大小的、有序的

为什么stream.empty()不具有stream.of()相同的特性?请注意,当它与stream.concat()结合使用时(特别是没有ordered)会产生影响。我想说stream.empty()不仅应该具有不可变和有序性,而且还应该具有DISTINCT和nonnull。stream.of()只有一个参数具有distict。

Q2:longstream.of()不具有非空值

刚刚注意到NONNULL在longstream.of中不可用。nonnull不是所有longstreams、intstreams和doublestreams的一个主要特性吗?

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

  • longrange.range(,):sumpled,IMMUTABLE,NONNULL,SIZED,ORDERED,SORTED,indistince
  • longstream.range(,).boxed():已添加、已调整大小、已排序

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

我知道.maptoobj()可能会丢失非空、不可变和DISTICT,但.boxed()...没道理。

Q4:.peek()丢失不可变和非空

LongStream.of(1):已沉降,不可变,非空,大小已定,...LongStream.of(1).peek():已沉降,大小已定,...

为什么.peek()会失去这些特性?.peek应该不会丢失任何东西。

Q5:.skip(),.limit()丢失已平息、不可变、非空、大小

请注意,这些操作丢失了sumved、IMMUTABLE、NONNULL、size。为什么?如果大小是可用的,那么计算最终大小也是很容易的。

Q6:.filter()丢失不可变、非空

请注意,这个操作同样会丢失summed、IMMUTABLE、NONNULL、size。失去sumded和size是有意义的,但其他两个就没有意义了。为什么?

我会很感激如果有人能深刻理解分裂者能带来一些澄清。多谢了。

共有1个答案

曹波鸿
2023-03-14

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

请考虑spliterator.immutable:

表示元素源不能进行结构修改的特征值;也就是说,不能添加、替换或移除元素,因此在遍历期间不能发生这样的更改。

在这个列表中看到“replaced”是很奇怪的,当谈到列表或数组时,它通常不被认为是结构修改,因此,接受数组(未克隆)的流和spliterator工厂报告不可变,如longstream.of(…)arrays.spliterator(Long[])

如果我们更慷慨地将其解释为“只要客户端无法观察到”,则concurrent没有显著区别,因为无论在哪种情况下,一些元素都将报告给客户端,而没有任何方法来识别它们是否是在遍历期间添加的,或者一些元素是否由于删除而未报告,因为没有方法来倒带拆分器并进行比较。

该规范继续:

不报告immutableconcurrent的拆分器应具有关于在遍历期间检测到的结构干扰的文档化策略(例如抛出concurrentModificationException)。

这是唯一相关的事情,报告immutableconcurrent的拆分器保证永远不会抛出concurrentModificationException。当然,concurrent在语义上排除了sized,但这对客户端代码没有任何影响。

事实上,这些特性并不用于流API中的任何内容,因此,不一致地使用它们不会在某些地方引起注意。

这也是为什么每个中间操作都具有清除并发不可变非空特性的效果的解释:流实现不使用这些特性,其表示流状态的内部类也不维护这些特性。

同样,nonnull也不会在任何地方使用,因此对于某些流不使用它没有任何影响。我可以追踪LongStream.of(…)发出的数组的内部使用。spliterator(Long[],int,int)委托
拆分器。spliterator(Long[]array,int fromIndex,int toIndex,int additionalcharacteres):

返回的拆分器总是报告特征sizedsumved。调用方可以提供附加特征以供拆分器报告。(例如,如果已知数组不会被进一步修改,请指定immutable;如果认为数组数据具有偶遇顺序,请指定ordered)。通常可以使用arrays.spliterator(long[],int,int)方法,该方法返回报告sizedsumpededimmutableordered的拆分器。

注意(再次)immutable特性的使用不一致。它再次被视为必须保证没有任何修改,同时arrays.spliterator以及arrays.streamlongstream.of(…)将报告immutable特性,即使按照规范,也不能保证调用方不会修改它们的数组。除非我们考虑设置一个元素不是一个结构修改,但是这样,整个区别又变得毫无意义了,因为数组不能进行结构修改。

并且明确规定了无nonnull特性。虽然很明显,基元值不能是null,而且spliterator.abstract spliterator 类总是注入非null特性,但spliterator.spliterator.spliterator.返回的spliterator.spliterator.不是从spliterator.abstractLongspliterator继承的。

坏处是,这不可能在不改变规范的情况下固定下来,好的是,反正没有任何后果。

因此,如果我们忽略concurrentimmutablenonnull的任何问题(这些问题没有任何后果),我们就有

大小跳过限制。这是一个众所周知的问题,它是由流API实现skiplimit方式的结果。其他的实现也是可以想象的。这也适用于无限流limit的组合,它应该具有可预测的大小,但给定当前的实现,它没有。

stream.concat(…)stream.empty()组合。一个空流不对结果顺序施加约束,这听起来很合理。但是stream.concat(…)在只有一个输入没有顺序时释放顺序的行为是值得怀疑的。请注意,在订购方面过于激进并不是什么新鲜事,请看这篇关于一种行为的问答,这种行为最初被认为是故意的,但后来在Java 8更新60中被修正了。也许,stream.concat也应该在此时讨论…

.boxed()的行为很容易解释。当它像.maptoOBJ(Long::ValueOf)那样幼稚地实现时,它就会使所有的知识松散,因为maptoOBJ不能假定结果仍然是排序的或不同的。但Java ;9已经解决了这一问题。其中,LongStream.Range(0,10).Boxed()具有SublizedSizedOrderedSortedDistinct特性,保持与实现相关的所有特性。

 类似资料:
  • 问题内容: 为了尝试深入了解Java流和分隔符,我对 分隔符的特性 提出了一些微妙的问题: Q1:vs(不带参数的Stream.of()) :已 订阅 :已 预订, 不可 更改,已 预订 ,已 订购 为什么没有相同的特征?请注意,与Stream.concat()结合使用时会产生影响(特别是没有)。我要说的不仅应该是 IMMUTABLE和ORDERED ,还应该是 DISTINCT和NONNULL

  • 本文向大家介绍require.js深入了解 require.js特性介绍,包括了require.js深入了解 require.js特性介绍的使用技巧和注意事项,需要的朋友参考一下 现在,Require.js是我最喜欢的Javascript编程方式。它可以使代码化整为零,并易于管理。而Require.js Optimizer能帮助我们将一个较大的应用分散成多个较小的应用,并通过依赖串联起来,最后在编

  • logstash 已经拥有数以百计的插件,并提供了一站式的部署方式,极大的方便了新手入门。但在实际运用上,我们终究会碰上其他人还没碰到过,或者碰到过但没公布出来完整解决方案的问题。可能是某些环境适配,可能是某个环节的性能不佳,可能是某处硬编码设置不合理,等等等等。这时候,了解一些 logstash 的代码逻辑,了解 logstash 之所以做出当前选择的缘由。是有助于解决实际问题的。 此外,log

  • 问题内容: 我试图了解如何使用Golang和forks。情况如下,我在写一个依赖于library的库,这不是我的。 由于缺少我需要的一些方法,因此将其分叉到。但是,我不能只是这样做,库引用了自己,所以它坏了。 在本文中,他们提供了可能的解决方案: 现在,这充其量是hacky。从库代码中无法得知依赖项来自其他存储库。任何使用我的图书馆的人都无法使其正常运行。 由于dep有望成为正式的依赖管理器。我发

  • 在这本教程的一开始 (第 6 章, 构建脚本基础) 你已经学习了如何创建简单的任务. 然后你也学习了如何给这些任务加入额外的行为, 以及如何在任务之间建立依赖关系. 这些仅仅是用来构建简单的任务. Gradle 可以创建更为强大复杂的任务. 这些任务可以有它们自己的属性和方法. 这一点正是和 Ant targets 不一样的地方. 这些强大的任务既可以由你自己创建也可以使用 Gradle 内建好的

  • 问题内容: 我在理解Java 8中的接口时遇到了麻烦,尤其是在与and 接口有关的地方。我的问题是我根本无法理解和接口的是,作为一个结果,接口仍然有些模糊了我。 和和到底是什么,我如何使用它们?如果我愿意写我自己或(和可能是我自己在这个过程中),我应该怎样做和不能做? 我阅读了一些分散在网络上的示例,但是由于此处的所有内容仍然是新内容并且随时可能更改,因此示例和教程仍然非常稀疏。 问题答案: 几乎