2017-07-17 5 views
1

ストリームを使用して文字列配列をハッシュマップに変換しています。パラレルストリームが要素の完全なリストを提供できない理由

String[] arguments= new String[]{"-a","1","-b","2","-c","3","-d","4","-e","5"}; 
    HashMap<String, String> params = new HashMap<>(); 
    IntStream.iterate(0, i -> i + 2) 
      .limit(arguments.length/2) 
      .parallel() 
      .forEach(i -> params.put(arguments[i], arguments[i + 1])); 
    System.out.println(params.size()); 

それは5を示し、時には4

あなたは異なる結果の理由で何ができるか、してください説明してもらえますか?

+0

* *なぜ「私は**ストリームを使用して文字列配列ハッシュマップするために**を変換しています」:

はそれを行うための正しい方法を介して収集することでしょうか?通常の 'for'ループを使います。それはより速く、よりシンプルで、より明確で、それは機能します! – Andreas

+0

ステップ1: 'forEach'なしで問題を解決するための学習。ステップ2:パラレルストリームがそのような些細なタスク(特に、パラレル非友好的な 'iterate(...).limit(...) 'コンボではない)を支払わないことを認識します。効率的なソリューションが必要な場合は、 'HashMap params = IntStream.range(0、arguments.length/2).map(i - > i * 2).collect(HashMap :: new、 Map :: putAll); 'これは並行して動作しますが、ここでは並列処理の利点はありません。 – Holger

答えて

1

基本的なストリームプロパティを壊しています。副作用はありません。あなたのストリームにはforEachで副作用があります。簡単な言葉で言えば、複数のスレッドの要素をスレッドセーフでないコレクションHashMapに入れます。

String[] arguments = new String[] { "-a", "1", "-b", "2", "-c", "3", "-d", "4", "-e", "5" }; 
    Map<String, String> map = IntStream.iterate(0, i -> i + 2) 
      .limit(arguments.length/2) 
      .parallel() 
      .boxed() 
      .collect(Collectors.toMap(i -> arguments[i], i -> arguments[i + 1])); 

    System.out.println(map); // {-a=1, -b=2, -c=3, -d=4, -e=5} 
1

並列ストリームで作業する場合、操作はステートレスでなければなりません。スレッドスケジューリングの違いがあると、結果が不確定になります。

このライン:

.forEach(i -> params.put(arguments[i], arguments[i + 1])); 

は、各実行で異なる結果の原因です。

collect還元操作を利用し、forEachを避けることで問題を解決できます。

あなたはJAVA Stream APIステートレス行動や副作用に関する詳細な情報を見つけることができます。

関連する問題