web-dev-qa-db-ja.com

深くスプリッターの特性を理解する

Javaストリームとスプリッターを深く理解するために、スプリッターの特性について微妙な質問があります:

Q1:Stream.empty() vs Stream.of()(Stream.of()引数なし)

  • Stream.empty() SUBSIZED、SIZED
  • Stream.of() SUBSIZED、[〜#〜] immutable [〜#〜]、SIZED、[ 〜#〜]順序付け[〜#〜]

Stream.empty()Stream.of()と同じ特性がないのはなぜですか? Stream.concat()と組み合わせて使用​​すると影響があることに注意してください(特にORDEREDがない場合)。 Stream.empty()には IMMUTABLEとORDERED だけでなく、 DISTINCTとNONNULL も必要です。また、 [〜#〜] distict [〜#〜] を持つ1つの引数のみでStream.of()も意味があります。

Q2:LongStream.of() [〜#〜] nonnull [〜#〜] がありません

NONNULLは_LongStream.of_では使用できないことに注意してください。 NONNULLはすべてのLongStreams、IntStreamsおよびDoubleStreamsの主な特徴ではありませんか?

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

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

なぜ.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 を失うことは理にかなっていますが、他の2つは意味がありません。どうして?


スプリッターを深く理解している誰かがいくつかの明確さをもたらすことができれば私は感謝します。ありがとう。

57
Tet

私は特性の実際の意味を最初に見つけようとしたときにも困難があったことを認めざるを得ません。また、その意味はJava 8の実装フェーズでは明確に解決されておらず、そのため一貫して使用されていないと感じていました。

Spliterator.IMMUTABLE を検討してください:

要素のソースを構造的に変更できないことを示す特性値。つまり、要素を追加、置換、または削除できないため、トラバーサル中にこのような変更を行うことはできません。

このリストで「置き換え」が見られるのは奇妙です。これは、Listまたは配列と言えば、通常は構造変更とは見なされず、その結果、配列(クローンではない)を受け入れるストリームおよびスプリッターファクトリーレポートIMMUTABLELongStream.of(…)またはArrays.spliterator(long[])など。

これを「クライアントが監視できない限り」とより寛大に解釈した場合、CONCURRENTに大きな違いはありません。どちらの場合もsome要素はクライアントに報告されず、それらが走査中に追加されたかどうか、または一部が削除のために報告されなかったかどうかを認識する方法。スプリッターを巻き戻して比較する方法がないためです。

仕様は続きます:

IMMUTABLEまたはCONCURRENTを報告しないSpliteratorには、トラバーサル中に検出された構造的干渉に関する文書化されたポリシー(たとえば、ConcurrentModificationExceptionのスロー)が必要です。

そして、これが唯一の関連事項であり、IMMUTABLEまたはCONCURRENTのいずれかがスプリテレーターを報告し、ConcurrentModificationExceptionをスローしないことが保証されています。もちろん、CONCURRENTは意味的にSIZEDを排除しますが、これはクライアントコードに影響を与えません。

実際、これらの特性はStream APIでは何にも使用されていないため、一貫性のない使用はどこかで気付かれることはありません。

every中間操作がCONCURRENTIMMUTABLEおよびNONNULLの特性をクリアする効果がある理由もこれです。Stream実装はそれらを使用せず、ストリームの状態を表す内部クラスはそれらを維持しません。


同様に、NONNULLはどこでも使用されないため、特定のストリームが存在しない場合は効果がありません。 LongStream.of(…)の問題を、デリゲートするArrays.spliterator(long[], int, int)の内部使用まで追跡できます
Spliterators.spliterator​(long[] array, int fromIndex, int toIndex, int additionalCharacteristics)

返されたスプリッターは常に特性SIZEDおよびSUBSIZEDを報告します。呼び出し元は、スプリテレーターが報告する追加の特性を提供できます。 (たとえば、配列がそれ以上変更されないことがわかっている場合は、IMMUTABLEを指定します。配列データが遭遇順序を持つと見なされる場合は、ORDEREDを指定します)。代わりにメソッドArrays.spliterator(long[], int, int)を使用できます。これは、SIZEDSUBSIZEDIMMUTABLE、およびORDEREDを報告するスプリッターを返します。

(繰り返しますが)IMMUTABLE特性の一貫性のない使用に注意してください。変更がないことを保証する必要があるように再び扱われますが、Arrays.spliterator、そしてArrays.streamLongStream.of(…)は、仕様によっても、[[SOME_VARIABLE] _特性を報告できますが、呼び出し元が配列を変更しないことを保証します。要素を構造的変更ではないように設定することを検討しない限り、配列は構造的に変更できないため、全体の区別は再び無意味になります。

そして、IMMUTABLEcharacteristicを明確に指定していません。プリミティブ値をNONNULLにできないことは明らかであり、Spliterator.Abstract<Primitive>Spliteratorクラスは常にnull特性を注入しますが、Spliterators.spliterator​(long[],int,int,int)によって返されるスプリッターはSpliterator.AbstractLongSpliteratorから継承しません。

悪い点は、仕様を変更せずにこれを修正できないことです。良い点は、とにかく影響がないことです。


したがって、結果のないNONNULLCONCURRENT、またはIMMUTABLEの問題を無視すると、

NONNULLおよびSIZEDskip。これはよく知られている問題で、limitおよびskipがStream APIによって実装された方法の結果です。他の実装も考えられます。これは、無限のストリームとlimitの組み合わせにも適用されます。limitは予測可能なサイズでなければなりませんが、現在の実装ではそうではありません。

Stream.concat(…)Stream.empty()の組み合わせ。空のストリームがnotを実行することは結果の順序に制約を課すことは理にかなっているようです。ただし、Stream.concat(…)の1つの入力だけに順序がない場合に順序を解放する動作には疑問があります。順序付けに関してあまりにも積極的であることは新しいことではないことに注意してください。最初は意図的であると見なされていたが、Javaまで修正された動作については this Q&A を参照してください8、更新60。おそらく、Stream.concatもこの時点で議論されているはずです…

.boxed()の動作は簡単に説明できます。 .mapToObj(Long::valueOf)のように単純に実装されている場合、mapToObjは結果がまだソートまたは区別されているとは想定できないため、すべての知識が失われます。しかし、これはJava 9で修正されています。LongStream.range(0,10).boxed()にはSUBSIZED|SIZED|ORDERED|SORTED|DISTINCTの特性があり、実装に関連するすべての特性を維持しています。

35
Holger