2017-05-03 6 views
6

私はJDK-8の下Collectors.toSet実装を見ていたし、ほとんどは明白なことを見た:一瞬combinerCollectors.toSet実装の詳細

public static <T> Collector<T, ?, Set<T>> toSet() { 
    return new CollectorImpl<>(
     (Supplier<Set<T>>) HashSet::new, 
     Set::add, 
     (left, right) -> { left.addAll(right); return left; }, // combiner 
     CH_UNORDERED_ID); 

ルック。これはhereの前に議論されていましたが、考え方はa combiner folds from the second argument into the firstです。それは明らかにここで起こります。

しかし、その後、私はjdk-9実装に見て、これを見た:

public static <T> Collector<T, ?, Set<T>> toSet() { 
    return new CollectorImpl<>(
     (Supplier<Set<T>>) HashSet::new, 
     Set::add, 
     (left, right) -> { 
      if (left.size() < right.size()) { 
      right.addAll(left); return right; 
      } else { 
      left.addAll(right); return left; 
      } 
     }, 
     CH_UNORDERED_ID); 

なぜこの問題が発生したが、少し明白である - それはless elements to a bigger Set, then the other way aroundを追加するにはあまり時間がかかります。しかし、それは普通のaddAllよりも実際に安いですか、ブランチに余分なオーバーヘッドがあると考えていますか?

また、これは常に左の折りたたみについての私のを破る...

誰かがここにいくつかの光を当てることができますか?維持する出会い順序がある場合

+1

私はわからないんだけど、私はあなたの質問を理解する。あなたはすでに 'jdk-9'実装のパフォーマンスの理論的根拠を理解しています。ずっと効率の悪いプログラムになった場合、なぜあなたのこの法律が支持されると思いますか? – gyre

+0

あなたの法律がその回答に反映されているかどうかはわかりません。 * left *を一貫して折りたたむことについては何も指定されていません。特に順序付けされたストリームと順序付けられていないストリームの区別を与える受け入れられた答えには何も指定されていません。 – gyre

+0

@gyreあなたは正しいかもしれない。少し急いで質問するようだ。 – Eugene

答えて

10

Collectorのコンバイナ機能が適切leftrightを受け取ることになります、しかし、それは実際にこれらの二つの引数を結合する方法、Collectorまでです。

documentation状態:

2つの部分的な結果を受け入れ、それらをマージする機能。コンバイナ関数は、一方の引数から他方の引数に状態を折りたたみ、それを返したり、新しい結果コンテナを返すことがあります。 Listに収集するための

我々だけright.addAll(left)left.addAll(right)を交換すれば、それは悲惨なことだろうが、順不同Setのために、それは問題ではありません。 toSet()コレクタは、leftまたはrightとして提供される引数に関係なく、Stream(または任意のクライアントコード)にヒントするようにUNORDEREDの特性を報告するため、パラレルストリームは、つまり、ソースにエンカウンターオーダーがあっても(Java 8の実装ではその機会が使用されていなくても)、順序付けられていないストリームのように動作する可能性があります。それは価値があるかどうかについて

...我々は、我々は保存することができますadd操作の潜在的何千もの複数の内部条件分岐をもつそれらの各を単一の追加ブランチを比較している...

関連する問題