8

この些細なプログラムがあれば言ってください

    List<String> input = Arrays.asList("1", "2", "3");
    List<String> result = input.stream()
            .map(x -> x + " " + x)
            .filter(y -> !y.startsWith("1"))
            .collect(Collectors.toList());

舞台裏では a) または b) のように動作しますか?

map
  "1" + " " + "1"
  "2" + " " + "2"
  "3" + " " + "3"
filter
  "1 1" does not begin with "1"? = false
  "2 2" does not begin with "1"? = true
  "3 3" does not begin with "1"? = true
collect
  add "2 2" to list
  add "3 3" to list
result = List("2 2", "3 3")

B

map
  "1" + " " + "1"
filter
  "1 1" does not begin with "1"? = false
map
  "2" + " " + "2"
filter
  "2 2" does not begin with "1"? = true
collect
  add "2 2" to list
map
  "3" + " " + "3"
filter
  "3 3" does not begin with "1"? = true
collect
  add "3 3" to list
result = List("2 2", "3 3")
4

2 に答える 2

8

これはオプション B のように機能しますが、必ずしもその正確な順序である必要はありませんが、一度に 1 つの要素に対してすべての操作を実行するという点でより優れています。

この背後にある理由は、変数がストリームを 1 回しか通過しないためです。そのため、要素が通過した時点ですべてのアクションを実行する必要があります。これは、要素が通過すると (ストリームの観点から) 永遠に失われるためです。

あなたのコードは、線形設定では、次のコードと非常に非常に大まかに同等です。これは非常に単純化されたバージョンですが、アイデアが得られることを願っています:

Collection<String> input = Arrays.asList("1", "2", "3");
Function<String, String> mapper = x -> x + " " + x;
Predicate<String> filter = y -> !y.startsWith("1");
Collector<String, ?, List<String>> toList = Collectors.toList();

List<String> list = ((Supplier<List<String>>)toList.supplier()).get();
for (String in : input) {
    in = mapper.apply(in);
    if (filter.test(in)) {
        ((BiConsumer<List<String>, String>)toList.accumulator()).accept(list, in);
    }
}

ここに表示される内容は次のとおりです。

  • 入力 a としてCollection<String>あなたの入力。
  • Function<String, String>一致するあなたのmap()
  • Predciate<String>一致するあなたのfilter()
  • Collector<String, ?, List<String>>一致するcollect()、これはタイプ の要素を操作するコレクターでありString、中間ストレージ?を使用してList<String>.

次に行うことは次のとおりです。

  • Supplier<List<String>>コレクターのサプライヤー (タイプ: ) から新しいリストを取得します。
  • で操作するときに内部的に行われる、入力のすべての要素をループします。ここでは、古い Java 7 の世界への接続を維持できるように、明確にするためにStream<String>a を使用しています。Collection<String>
  • マッピング関数を適用します。
  • フィルター述語をテストします。
  • コレクターのアキュムレーター (タイプ: BiConsumer<List<String>, String>) を取得します。これは、既に持っているtoListを引数として取り、追加したい を受け取るバイナリー・コンシューマーです。List<String>String
  • アキュムレータにlistandを供給します。in

操作は任意の順序で発生し、複数の操作が発生する可能性があるため、実際の実装ははるかに高度であることに注意してください。

于 2014-03-29T20:01:49.717 に答える
5

ストリームの利点の 1 つは、中間操作の遅延評価です。つまり、端末操作 (collect()この場合は) が実行されると、前の中間操作 - から要素を要求します。これfilter()は、 から要素を取得し、 からmap()最初の要素を操作しlist.stream()ます。すべての要素について同じフローに従います。はい、実行はオプション B に似ています。

また、によって返されるコレクターCollectors.toList()は順序付けられているため、要素は順序どおりに実行されることが保証されます。UNORDEREDコレクターに特性を設定すると、評価が狂う場合があります。

于 2014-03-29T20:03:40.987 に答える