2013-10-22 29 views
25

JDK 8 EAがリリースされました。ラムダと新しいStream APIに慣れようとしています。私は、並列ストリームのリストをソートするために試してみたが、結果は常に間違っている:java 8 parallelStream()with sorted()

import java.util.ArrayList; 
import java.util.List; 

public class Test 
{ 
    public static void main(String[] args) 
    { 
     List<String> list = new ArrayList<>(); 
     list.add("C"); 
     list.add("H"); 
     list.add("A"); 
     list.add("A"); 
     list.add("B"); 
     list.add("F"); 
     list.add(""); 

     list.parallelStream() // in parallel, not just concurrently! 
      .filter(s -> !s.isEmpty()) // remove empty strings 
      .distinct() // remove duplicates 
      .sorted() // sort them 
      .forEach(s -> System.out.println(s)); // print each item 
    } 
} 

OUTPUT:出力が異なるたびこと

C 
F 
B 
H 
A 

注意。私の質問はバグですか?または並行してリストをソートすることはできないのですか?もしそうなら、なぜJavaDocはそれを述べていないのですか?最後の質問ですが、ストリームの種類によって出力が異なる別の操作がありますか?

+1

ソート後に重複を削除する方がよいでしょう。 – Ingo

答えて

44

forEachOrderedではなく、forEachを使用する必要があります。 forEachドキュメントを1として

:パラレルストリームパイプラインについては

そうすることが並列処理の利益を犠牲と同じように、この操作は、ストリームの出会いの順序を尊重することを保証するものではありません。どんな所与の要素についても、何時でも、ライブラリが選択するどのようなスレッドにおいても、アクションを実行することができる。アクションが共有状態にアクセスする場合は、必要な同期を提供する必要があります。

+1

+1素晴らしい!これは私が探していたものです。 –

+0

私の推測では、内部的には「ソート」リストが作成され、各スレッドはそのリストに追加され、フローの次のステップ(forEach)に進み、FWIW順不同で実行されます。 – rogerdpack

6

さらに、並列性とforEachOrderedの詳細については、hereの非常に優れた例を参照してください。まとめると、並列ストリームでforEachOrderedを使用すると、並列処理の利点が失われる可能性があります。

ここで同じリソースから例:

Integer[] intArray = {1, 2, 3, 4, 5, 6, 7, 8 }; 
List<Integer> listOfIntegers = 
    new ArrayList<>(Arrays.asList(intArray)); 

System.out.println("listOfIntegers:"); 
listOfIntegers 
    .stream() 
    .forEach(e -> System.out.print(e + " ")); 
System.out.println(""); 

System.out.println("listOfIntegers sorted in reverse order:"); 
Comparator<Integer> normal = Integer::compare; 
Comparator<Integer> reversed = normal.reversed(); 
Collections.sort(listOfIntegers, reversed); 
listOfIntegers 
    .stream() 
    .forEach(e -> System.out.print(e + " ")); 
System.out.println(""); 

System.out.println("Parallel stream"); 
listOfIntegers 
    .parallelStream() 
    .forEach(e -> System.out.print(e + " ")); 
System.out.println(""); 

System.out.println("Another parallel stream:"); 
listOfIntegers 
    .parallelStream() 
    .forEach(e -> System.out.print(e + " ")); 
System.out.println(""); 

System.out.println("With forEachOrdered:"); 
listOfIntegers 
    .parallelStream() 
    .forEachOrdered(e -> System.out.print(e + " ")); 
System.out.println(""); 

および出力

listOfIntegers: 
1 2 3 4 5 6 7 8 
listOfIntegers sorted in reverse order: 
8 7 6 5 4 3 2 1 
Parallel stream: 
3 4 1 6 2 5 7 8 
Another parallel stream: 
6 3 1 5 7 8 4 2 
With forEachOrdered: 
8 7 6 5 4 3 2 1 

である第五のパイプラインは、ストリームの 要素を処理forEachOrdered方法を使用しストリームをシリアルまたはパラレルで実行したかどうかにかかわらず、ソースによって指定されたオーダー、 あなたはパラレル・ストリーム

でforEachOrderedよう 操作を使用する場合は、並列処理のメリットを失う可能性が 注意。

+0

それは少し薄いです。回答を編集して拡大してください。 –