深刻理解分裂者的特征 [英] Understanding deeply spliterator characteristics
问题描述
为了尝试深入理解java流和分裂器,我对分裂器特征有一些微妙的问题:
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()
(没有args的Stream.of() )
Q1: Stream.empty()
vs Stream.of()
(Stream.of() without args)
-
Stream.empty()
: SUBSIZED,SIZED -
Stream.of()
: SUBSIZED, IMMUTABLE ,SIZED,已订购
Stream.empty()
: SUBSIZED, SIZEDStream.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
注意到NONNULL在 LongStream.of
中不可用。
不是 NONNULL
所有 LongStream的主要特征
s, IntStream
s和 DoubleStream
s?
Just noticed that NONNULL is not available in LongStream.of
.
Isn't NONNULL
a main characteristics of all LongStream
s, IntStream
s and DoubleStream
s?
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, DISTINCTLongStream.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.
表示元素源不能进行结构修改的特征值;也就是说,元素无法添加,替换或删除,因此在遍历期间不会发生此类更改。
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
或数组时通常不被视为结构修改,因此,流和spliterator工厂接受一个数组(未克隆)报告 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.
规范仍在继续:
未报告
IMMUTABLE
或CONCURRENT
的Spliterator应具有记录的策略(例如,抛出ConcurrentModificationException
)关于遍历期间检测到的结构干扰。
A Spliterator that does not report
IMMUTABLE
orCONCURRENT
is expected to have a documented policy (for example throwingConcurrentModificationException
) concerning structural interference detected during traversal.
这是唯一相关的事情,a spliterator报告, IMMUTABLE
或 CONCURRENT
,保证永远不会抛出 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.
这也解释为什么每个中间操作都有清除 CONCURRENT
的效果, IMMUTABLE
和 NONNULL
特征: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)
:
返回的分裂器总是报告特征
SIZED
和SUBSIZED
。呼叫者可以为分裂者报告提供额外的特征。 (例如,如果已知数组将不会被进一步修改,请指定IMMUTABLE
;如果数组数据被视为具有遭遇订单,请指定序
)。通常可以使用方法Arrays.spliterator(long [],int,int)
,这将返回报告SIZED $ c的分裂器$ c>,
SUBSIZED
,IMMUTABLE
,ORDERED
。
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
特征,即使按规范也是如此,而不是能够保证调用者不会修改他们的数组。除非我们考虑将元素设置为不是结构修改,否则,整个区别再次变得荒谬,因为数组不能在结构上进行修改。
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.Abstract< Primitive> Spliterator
类总是不变的注入一个 NONNULL
特征,由 Spliterators.spliterator返回的分裂器(long [],int,int,int)
不会继承自 Spliterator.AbstractLongSpliterator
。
And it clearly specified no NONNULL
characteristic. 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.
因此,如果我们忽略<$ c $的任何问题c> CONCURRENT , IMMUTABLE
或 NONNULL
,这没有任何后果,我们
So if we ignore any issues with CONCURRENT
, IMMUTABLE
, or NONNULL
, which have no consequences, we have
SIZED
和跳过
& 限制
。这是一个众所周知的问题,Stream API实现了 skip
和 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(...)
当只有一个输入没有订单时释放订单的行为是值得怀疑的。请注意,在订购方面过于激进并不是什么新鲜事,请参阅此Q& A ,了解有意首先考虑的行为,但然后已经修复了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屋!