11

2 番目のコード (ストリームを含むコード) が最初のコードよりも優れているのはなぜですか?

初め :

public static void main(String [] args) {
   List<Integer> values = Arrays.asList(1,2,3,4,5,6);
   int total = 0;
   for(int e : values) {
       total += e * 2;

   }

2番 :

   System.out.println(total);
   System.out.println(
           values.stream()
           .map(e-> e*2)
           .reduce(0, (c, e)-> c + e)); 
4

3 に答える 3

19

変異とはオブジェクトを変更することであり、プログラミング言語でよく見られる副作用の 1 つです。

関数コントラクトを持つメソッドは、常に同じ値を同じ引数に返し、他の副作用 (ファイルの保存、印刷、読み取りなど) はありません。したがって、関数内で一時的な値を変更しても、外部からは純粋です。最初の例を関数に入れると、次のようになります。

public static int squareSum(const List<Integer> values)
{
    int total = 0;
    for(int e : values) {
        total += e * 2;  // mutates a local variable
    }
    return total;
}

純粋に機能的なメソッドは、ローカル変数を更新しません。2 番目のバージョンを関数に入れると、純粋になります。

public static int squareSum(const List<Integer> values)
{
    return values.stream()
           .map(e-> e*2)
           .reduce(0, (c, e)-> c + e);
}

map長い間機能的なスタイルを好んreduceできた他の言語を知っている人にとっては、lambda非常に自然です。どちらのバージョンも読みやすく、テストも簡単です。これが最も重要な部分です。

Java には関数型クラスがあります。java.lang.Stringその一つです。

于 2015-06-05T19:23:02.053 に答える
5

Royal Bg は正しいですが、どちらの場合もデータを変更していませんが、2 番目のバージョンに利点がないというのは真実ではありません。2 番目のバージョンは、あいまいさなく高度にマルチスレッド化できます。

リストを反復することは想定していないため、操作を高度なマルチスレッド コンテキストに配置し、GPU で解決できます。後者では、コレクション内の各データ ポイントが 2 で乗算されます。次に、削減されます (つまり、すべての要素が一緒に加算されます)。これは、削減によって行うことができます。

後者のコードには、前者には見られない多くの潜在的な利点があります。どちらのコード要素も実際には変更されませんが、2 番目のコード要素では、変更が行われている間は項目が変更できないという非常に明確な契約が与えられています。したがって、リストを順方向、逆方向に反復するか、マルチスレッドに適用するかなどは問題ではないことがわかります。実装の詳細は後で入力できます。ただし、ミューテーションが発生しないことがわかっていて、ストリームが単にミューテーションを許可しない場合に限ります。

于 2017-01-11T01:02:30.287 に答える