当前位置: 首页 > 面试题库 >

深入了解分离器特性

缑桐
2023-03-14
问题内容

为了尝试深入了解Java流和分隔符,我对 分隔符的特性 提出了一些微妙的问题:

Q1:Stream.empty()vsStream.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所有LongStreams,IntStreams和DoubleStreams
的主要特征吗?

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

  • LongRange.range(,)SUBSIZED, IMMUTABLE,NONNULL ,SIZED,ORDERED, SORTED ,DISTINCT
  • 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,IMMUTABLE,NONNULL,SIZED 。失去 SUBSIZED和SIZED是
有意义的,但是其他两个则没有意义。为什么?

如果有人对分离器有深刻的了解,我可以感谢您。谢谢。


问题答案:

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

考虑Spliterator.IMMUTABLE

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

看到此列表中的“已替换”很奇怪,当谈到a
List或数组时,通常不将其视为结构修改,因此,流和分离器工厂接受数组(未克隆)的报告IMMUTABLE,例如LongStream.of(…)Arrays.spliterator(long[])

如果我们将其更宽泛地解释为“只要客户端无法观察到”,则不会有显着差异CONCURRENT,因为在两种情况下,都会向客户端报告 某些
元素,而无法识别在遍历期间是否添加了 这些 元素,或者是否由于无法移除,有些未报告,因为无法倒带分隔器并进行比较。

规范继续:

一个没有报告IMMUTABLECONCURRENT预期具有ConcurrentModificationException关于遍历过程中检测到的结构性干扰的书面策略(例如throw)的分隔器。

这是唯一相关的事情,保证分隔符报告IMMUTABLECONCURRENT永远不会抛出ConcurrentModificationException。当然,从语义上CONCURRENT排除SIZED,但这对客户端代码没有影响。

实际上,这些特性在Stream API中并未用于任何用途,因此,不一致地使用它们将永远不会在某处引起注意。

这也是的解释,为什么 每个
中间操作中具有清热的效果CONCURRENTIMMUTABLENONNULL特性:数据流实现不使用它们,代表流状态的内部类不维护他们。

同样,NONNULL在任何地方都不会使用它,因此某些流没有它不会起作用。我可以将LongStream.of(…)问题归结为内部使用Arrays.spliterator(long[],int, int)哪些代表 Spliterators.spliterator​(long[] array, int fromIndex, int toIndex, intadditionalCharacteristics)

返回的分隔符始终报告特性SIZEDSUBSIZED。调用方可以为分隔符提供其他特征以进行报告。(例如,如果知道不会进一步修改数组,请指定IMMUTABLE;如果认为数组数据具有相遇顺序,请指定ORDERED)。该方法Arrays.spliterator(long[], int, int)通常可以替代地使用,它返回一个spliterator该报告SIZEDSUBSIZEDIMMUTABLE,和ORDERED

再次注意该IMMUTABLE特性的不一致用法。它被再次处理等不必保证不存在任何变形,而在同一时间,Arrays.spliterator并依次Arrays.streamLongStream.of(…)将报告IMMUTABLE特性,即使是规格,而不能保证呼叫方将不会修改他们的阵列。除非我们考虑将元素设置为非结构性修改,否则整个区别将再次变得无意义,因为数组无法进行结构性修改。

而且它明确规定没有NONNULL特征。很明显,原始值不能为null,并且Spliterator.Abstract<Primitive>Spliterator类始终注入NONNULL特性,但返回的分隔符Spliterators.spliterator​(long[],int,int,int)不会继承自Spliterator.AbstractLongSpliterator

不好的是,这不能在不更改规格的情况下得到解决,而好的事情是,它没有任何后果。

因此,如果我们忽略了任何问题CONCURRENTIMMUTABLE或者NONNULL,它们没有什么后果,我们有

SIZEDskiplimit。这是一个众所周知的问题,是这种方法的结果,skip并且limit已由Stream
API实现。其他实现是可以想象的。这也适用于无限流与的组合,该组合limit应具有可预测的大小,但考虑到当前的实现,则没有。

Stream.concat(…)与结合Stream.empty()。这听起来是合理的空流并 没有
结果顺序施加约束。但是Stream.concat(…)当只有一个输入没有命令时,释放命令的行为值得怀疑。请注意,对订购太过激进并不是什么新鲜事,有关此行为的问与答(首先被认为是有意为之,但后来在Java
8,update 60中已得到修复)。也许Stream.concat在此时也应该进行讨论…

的行为.boxed()很容易解释。当像天真那样实施时.mapToObj(Long::valueOf),它将简单地失去所有知识,因为mapToObj不能假设结果仍然是排序或不同的。但这已在Java
9中修复。那里LongStream.range(0,10).boxed()具有一些SUBSIZED|SIZED|ORDERED|SORTED|DISTINCT特性,可以维护与实现相关的所有特性。



 类似资料:
  • 为了试图深入理解Java流和spliterator,我有一些关于spliterator特性的微妙问题: Q1:与(不带参数的stream.of()) :已沉降,大小 :沉降的、不可变的、有大小的、有序的 为什么不具有相同的特性?请注意,当它与stream.concat()结合使用时(特别是没有)会产生影响。我想说不仅应该具有不可变和有序性,而且还应该具有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 内建好的

  • 深入了解Bundle和Map 原文链接 : The mysterious case of the Bundle and the Map 译文出自 : 开发技术前线 www.devtf.cn 译者 : yinna317 校对者: chaossss 状态 : 翻译完成 前言 因为往Bundle对象中放入Map实际上没有表面上看起来那么容易。 这篇博客是在Eugenio @workingkills Ma