深入了解分离器特性 [英] Understanding deeply spliterator characteristics

查看:28
本文介绍了深入了解分离器特性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了深入理解java流和spliterator,我对spliterator特性有一些微妙的疑问:

In order to try to deeply understand java streams and spliterators, I have some subtle questions about spliterator characteristics:

Q1:Stream.empty() vs Stream.of()(Stream.of() 不带参数)

Q1: Stream.empty() vs Stream.of() (Stream.of() without args)

  • Stream.empty(): SUBSIZED, SIZED
  • Stream.of():SUBSIZED、IMMUTABLE、SIZED、ORDERED

为什么 Stream.empty() 没有 Stream.of() 的特性?请注意,它在与 Stream.concat() 结合使用时会产生影响(特别是没有 ORDERED).我会说 Stream.empty() 不仅应该具有 IMMUTABLE 和 ORDERED,还应该具有 DISTINCT 和 NONNULL.此外,Stream.of() 只有一个参数具有 DISTICT.

Why Stream.empty() doesn't have the same characteristics of Stream.of()? Note that it has impacts when using in conjunction with Stream.concat() (specially not having ORDERED). I would say that Stream.empty() should have not just IMMUTABLE and ORDERED but also DISTINCT and NONNULL. Also it make sense Stream.of() with only one argument having DISTICT.

Q2:LongStream.of() 没有 NONNULL

Q2: LongStream.of() not having NONNULL

刚刚注意到在 LongStream.of 中 NONNULL 不可用.NONNULL不是所有LongStreams、IntStreams和DoubleStreams的主要特征吗?

Just noticed that NONNULL is not available in LongStream.of. Isn't NONNULL a main characteristics of all LongStreams, IntStreams and DoubleStreams?

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

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

  • LongRange.range(,):SUBSIZED、IMMUTABLE、NONNULL、SIZED、ORDERED、SORTED、DISTINCT
  • LongStream.range(,).boxed(): SUBSIZED, SIZED, ORDERED
  • LongRange.range(,): SUBSIZED, IMMUTABLE, NONNULL, SIZED, ORDERED, SORTED, DISTINCT
  • LongStream.range(,).boxed(): SUBSIZED, SIZED, ORDERED

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

Why .boxed() loses all these characteristics? It shouldn't lose any.

我知道 .mapToObj() 可能会丢失 NONNULL、IMMUTABLE 和 DISTICT,但是 .boxed()... 不会'没道理.

I understand that .mapToObj() can lose the NONNULL, IMMUTABLE and DISTICT, but .boxed()... doesn't make sense.

Q4:.peek() 丢失 IMMUTABLE 和 NONNULL

Q4: .peek() loses IMMUTABLE and NONNULL

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

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

Why .peek() loses these characteristics? .peek shouldn't really lose any.

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

Q5: .skip(), .limit() loses SUBSIZED, IMMUTABLE, NONNULL, SIZED

请注意,这些操作丢失了SUBSIZED、IMMUTABLE、NONNULL、SIZED.为什么?如果尺寸可用,那么也很容易计算出最终尺寸.

Just notice that these operations loses SUBSIZED, IMMUTABLE, NONNULL, SIZED. Why? If the size is available, then it's easy to calculate the final size as well.

Q6:.filter() 丢失 IMMUTABLE, NONNULL

Q6: .filter() loses IMMUTABLE, NONNULL

请注意,此操作也会丢失SUBSIZED、IMMUTABLE、NONNULL、SIZED.丢失 SUBSIZED 和 SIZED 是有意义的,但其他两个没有意义.为什么?

Just notice that this operations loses as well SUBSIZED, IMMUTABLE, NONNULL, SIZED. It make sense to lose SUBSIZED and SIZED, but the others two doesn't make sense. Why?

如果有人深入了解拆分器可以带来一些清晰度,我将不胜感激.谢谢.

I will appreciate if someone that understands deeply the spliterator could bring some clarity. Thanks.

推荐答案

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

I have to admit that I had difficulties too when I first tried to find out the actual meaning of the characteristics and had the feeling that their meaning was not clearly settled during the implementation phase of Java 8 and is used inconsistently for that reason.

考虑 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.

在这个列表中看到replaced"很奇怪,当谈到 List 或数组时,通常不被认为是结构修改,因此流和拆分器工厂接受数组(即未克隆)报告 IMMUTABLE,例如 LongStream.of(…)Arrays.spliterator(long[]).

It’s strange to see "replaced" in this list, which is usually not considered a structural modification when speaking of a List or an array and consequently, stream and spliterator factories accepting an array (that is not cloned) report IMMUTABLE, like LongStream.of(…) or Arrays.spliterator(long[]).

如果我们更慷慨地将其解释为只要客户端无法观察到",则 CONCURRENT 没有显着差异,因为在任何一种情况下,某些 元素都会报告给客户端,而无法识别它们是在遍历过程中添加的,还是由于删除而未报告的,因为无法倒带拆分器并进行比较.

If we interpret this more generously as "as long as not observable by the client", there is no significant difference to CONCURRENT, as in either case some elements will be reported to the client without any way to recognize whether they were added during traversal or whether some were unreported due to removal, as there is no way to rewind a spliterator and compare.

规范继续:

不报告 IMMUTABLECONCURRENT 的 Spliterator 应具有有关检测到的结构干扰的文档化策略(例如抛出 ConcurrentModificationException)在遍历过程中.

A Spliterator that does not report IMMUTABLE or CONCURRENT is expected to have a documented policy (for example throwing ConcurrentModificationException) concerning structural interference detected during traversal.

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

And that’s the only relevant thing, a spliterator reporting either, IMMUTABLE or CONCURRENT, is guaranteed to never throw a ConcurrentModificationException. Of course, CONCURRENT precludes SIZED semantically, but that has no consequence to the client code.

事实上,Stream API 中没有使用这些特性,因此,不一致地使用它们永远不会在某处引起注意.

In fact, these characteristics are not used for anything in the Stream API, hence, using them inconsistently would never get noticed somewhere.

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

This is also the explanation why every intermediate operation has the effect of clearing the CONCURRENT, IMMUTABLE and NONNULL characteristics: the Stream implementation doesn’t use them and its internal classes representing the stream state do not maintain them.

同样,NONNULL 没有在任何地方使用,所以它的缺失对某些流没有影响.我可以将 LongStream.of(…) 问题追溯到 Arrays.spliterator(long[], int, int) 的内部使用,它委托给
Spliterators.spliterator (long[] array, int fromIndex, int toIndex, int additionalCharacteristics):

Likewise, NONNULL is not used anywhere, so it’s absence for certain streams has no effect. I could track down the LongStream.of(…) issue down to the internal use of Arrays.spliterator(long[], int, int) which delegates to
Spliterators.spliterator​(long[] array, int fromIndex, int toIndex, int additionalCharacteristics):

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

The returned spliterator always reports the characteristics SIZED and SUBSIZED. The caller may provide additional characteristics for the spliterator to report. (For example, if it is known the array will not be further modified, specify IMMUTABLE; if the array data is considered to have an encounter order, specify ORDERED). The method Arrays.spliterator(long[], int, int) can often be used instead, which returns a spliterator that reports SIZED, SUBSIZED, IMMUTABLE, and ORDERED.

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

Note (again) the inconsistent use of the IMMUTABLE characteristic. It is again treated like having to guaranty the absence of any modification, while at the same time, Arrays.spliterator and in turn Arrays.stream and LongStream.of(…) will report the IMMUTABLE characteristic, even by specification, without being able to guaranty that the caller won’t modify their array. Unless we consider setting an element not to be a structural modification, but then, the entire distinction becomes nonsensical again, as arrays can’t be structurally modified.

并且它明确指定没有NONNULL特性.虽然很明显原始值不能是 null,并且 Spliterator.AbstractSpliterator 类总是注入一个 NONNULL 特性,Spliterators.spliterator (long[],int,int,int) 返回的拆分器不是从 Spliterator.AbstractLongSpliterator 继承的.

And it clearly specified no NONNULLcharacteristic. While it is obvious that primitive values can’t be null, and the Spliterator.Abstract<Primitive>Spliterator classes invariably inject a NONNULL characteristic, the spliterator returned by Spliterators.spliterator​(long[],int,int,int) does not inherit from Spliterator.AbstractLongSpliterator.

不好的是,如果不改变规范就无法解决这个问题,好的是,无论如何它没有任何后果.

The bad thing is, this can’t be fixed without changing the specification, the good thing is, it has no consequences anyway.

因此,如果我们忽略 CONCURRENTIMMUTABLENONNULL 的任何问题,它们没有任何后果,我们有

So if we ignore any issues with CONCURRENT, IMMUTABLE, or NONNULL, which have no consequences, we have

SIZEDskip &限制.这是一个众所周知的问题,是 Stream API 实现 skiplimit 方式的结果.其他实现是可以想象的.这也适用于无限流与 limit 的组合,它应该具有可预测的大小,但鉴于当前的实现,还没有.

SIZED and skip & limit. This is a well known issue, result of the way skip and limit have been implemented by the Stream API. Other implementations are imaginable. This also applies to the combination of an infinite stream with a limit, which should have a predictable size, but given the current implementation, has not.

结合 Stream.concat(…)Stream.empty().空流不会对结果顺序施加约束,这听起来很合理.但是 Stream.concat(…) 在只有一个输入没有订单时释放订单的行为是值得怀疑的.请注意,对排序过于激进并不是什么新鲜事,请参阅此问答,了解首先被认为是故意的行为,但then 已在 Java 8 更新 60 中得到修复.也许,Stream.concat 也应该在此时讨论......

Combining Stream.concat(…) with Stream.empty(). It sounds reasonable that an empty stream does not impose constraints on the result order. But Stream.concat(…)’s behavior of releasing the order when only one input has no order, is questionable. Note that being too aggressive regarding ordering is nothing new, see this Q&A regarding a behavior that was considered intentional first, but then has been fixed as late as Java 8, update 60. Perhaps, Stream.concat should have been discussed right at this point of time too…

.boxed() 的行为很容易解释.当它像 .mapToObj(Long::valueOf) 那样天真地实现时,它只会丢失所有的知识,因为 mapToObj 不能假设结果仍然是排序的或清楚的.但这已在 Java 9 中修复.在那里,LongStream.range(0,10).boxed() 具有 SUBSIZED|SIZED|ORDERED|SORTED|DISTINCT 特性,保持与实施相关的所有特征.

The behavior of .boxed() is easy to explain. When it has been implemented naively like .mapToObj(Long::valueOf), it will simply loose all the knowledge, as mapToObj can not assume that the result is still sorted or distinct. But this has been fixed with Java 9. There, LongStream.range(0,10).boxed() has SUBSIZED|SIZED|ORDERED|SORTED|DISTINCT characteristics, maintaining all characteristics that have relevance to the implementation.

这篇关于深入了解分离器特性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆