私はストリームの抽象化に関する Java 8 API を読んでいますが、この文はあまりよくわかりません。
中間操作は新しいストリームを返します。それらは常に怠け者です。 filter()などの中間操作を実行しても、実際にはフィルタリングは実行されませんが、代わりに、指定された述語に一致する初期ストリームの要素を含む新しいストリームが作成されます。パイプラインソースのトラバースは、パイプラインのターミナル操作が実行されるまで開始されません。
フィルター操作が新しいストリームを作成するとき、そのストリームにはフィルターされた要素が含まれていますか?ストリームが要素を含むのは、それが端末操作でトラバースされたときだけであることを理解しているようです。しかし、それよりも、フィルタリングされたストリームには何が含まれていますか?よくわかりません!!!
これは、フィルターが端末操作中にのみ適用されることを意味します。次のようなものを考えてください:
public Stream filter(Predicate p) {
this.filter = p; // just store it, don't apply it yet
return this; // in reality: return a new stream
}
public List collect() {
for (Object o : stream) {
if (filter.test(o)) list.add(o);
}
return list;
}
(それはコンパイルされず、現実の単純化ですが、原則はそこにあります)
端末操作が呼び出されない限り、中間操作は評価されないため、ストリームは遅延します。
各中間操作は新しいストリームを作成し、提供された操作/関数を保存し、新しいストリームを返します。
パイプラインは、これらの新しく作成されたストリームを蓄積します。
端末操作が呼び出され、ストリームのトラバースが開始され、関連する機能が1つずつ実行される時間。
パラレルストリームは、ストリームを1つずつ(終点で)評価しません。使用可能なコアに応じて、操作はむしろ同時に実行されます。
私には、その中間操作は正確に怠zyではないようです:
List<String> l3 = new ArrayList<String>();
l3.add("first");
l3.add("second");
l3.add("third");
l3.add("fouth");
l3.add("fith");
l3.add("sixth");
List<String> test3 = new ArrayList<String>();
try {
l3.stream().filter(s -> { l3.clear(); test3.add(s); return true;}).forEach(System.out::println);
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("!!! ");
System.out.println(test3.stream().reduce((s1, s2) -> s1 += " ;" + s2).get());
}
出力:
first
null
null
null
null
null
Java.util.ConcurrentModificationException
at Java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.Java:1380)
at Java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.Java:481)
at Java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.Java:471)
at Java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.Java:151)
at Java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.Java:174)
at Java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.Java:234)
at Java.util.stream.ReferencePipeline.forEach(ReferencePipeline.Java:418)
at test.TestParallel.main(TestParallel.Java:69)
!!!
first ;null ;null ;null ;null ;null
ストリーム作成時の反復セットの数のように見えますが、新しいストリーム要素が遅延します。
カウンター付きループと比較してください:
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
int i = 0;
while (i < list.size()) {
System.out.println(list.get(i++));
list.clear();
}
}
出力:
1
予想される反復は1つだけです。私はストリームで例外をスローする動作の問題に同意しますが、怠zyはデータを取得する(または何らかのアクションを実行する)ことを意味します。データの数もデータです。