map()
とfilter()
のOptional
は、Stream
のように怠惰ですか?マップの種類()とフィルタ()操作のオプション
どのようにタイプを確認できますか?
この実行している一方
abcdefjklマップ、第一のフィルタ、マッピングを実行する:
map()
とfilter()
のOptional
は、Stream
のように怠惰ですか?マップの種類()とフィルタ()操作のオプション
どのようにタイプを確認できますか?
この実行している一方
abcdefjklマップ、第一のフィルタ、マッピングを実行する:
Stream
とOptional
の間に基本的な違いがあります。
Stream
は、処理パイプライン全体をカプセル化し、処理を行う前にすべての操作を収集します。これにより、実装が実際に要求された結果に応じて異なる処理方法を選択することができます。これにより、unordered()
やparallel()
のような修飾子をチェーンに挿入することができます。この時点では何も行われていないので、その後の実際の処理の動作を変更することができます。
極端な例がStream.of(1, 2, 3).map(function).count()
であり、3
の不変の結果がなくても、Java 9で全くfunction
を処理しません。
対照的に、Optional
は値の周りのラッパー(空でない場合)です。各操作は即座に実行され、新しい値をカプセル化する新しいOptional
または空のOptional
を返します。 Java 8では、Optional
を返すすべてのメソッド、つまりmap
,flatMap
またはfilter
は、空のオプションに適用すると空のオプションを返すだけなので、空のオプションは一種のデッドエンドになります。
しかし、Java 9ではOptional<T> or(Supplier<? extends Optional<? extends T>>)
が導入されました。空のオプションに適用された場合、サプライヤから空ではないオプションが返される可能性があります。
Optional
は(おそらく不在)値ではなく、処理パイプラインを表しているので、あなたは、クエリが新しいOptional
または最終値を返すかどうか、あなたが望む同じOptional
な回数を照会することができます。
確認するのは簡単です。次のコード
Optional<String> first=Optional.of("abc");
Optional<String> second=first.map(s -> {
System.out.println("Running map");
return s + "def";
});
System.out.println("starting queries");
System.out.println("first: "+(first.isPresent()? "has value": "is empty"));
System.out.println("second: "+(second.isPresent()? "has value": "is empty"));
second.map("second's value: "::concat).ifPresent(System.out::println);
は、マッピング関数は、他のクエリの前に、すぐに評価されていることを実証し
Running map
starting queries
first: has value
second: has value
second's value: abcdef
が印刷されます、と私たちはmap
とを介して第二の作成した後、我々はまだfirst
オプションを照会することができるということクエリオプションを複数回使用します。
実際にはをisPresent()
経由で確認することを強くお勧めします。get()
を呼び出してください。
Stream
インスタンスを再使用すると、この方法は無効です。同等のストリームコードはありません。しかし、我々は、端末操作が開始される前に中間操作が実行されていないことを示すことができる:
Stream<String> stream=Stream.of("abc").map(s -> {
System.out.println("Running map");
return s + "def";
});
System.out.println("starting query");
Optional<String> result = stream.findAny();
System.out.println("result "+(result.isPresent()? "has value": "is empty"));
result.map("result value: "::concat).ifPresent(System.out::println);
は、マッピング機能が端末操作findAny()
開始前に評価されていないことを示す
starting query
Running map
result has value
result value: abcdef
を印刷します。ストリームを複数回照会することはできないので、findAny()
は戻り値としてOptional
を使用します。これにより、最終結果でストリームを行うことができます。
同じ名前の操作間には他の意味の違いがあります。 Optional.map
は、マッピング関数がnull
と評価された場合は空のOptional
を返します。ストリームの場合、map
に渡された関数がnull
またはnull
という値を返すかどうかは関係ありません(そのため、要素が何をするかを知らずに要素を数えることができます)。
String r = Optional.of("abc")
.map(s -> {
System.out.println("Running map");
return s + "def";
})
.filter(s -> {
System.out.println("First Filter");
return s.equals("abcdef");
})
.map(s -> {
System.out.println("mapping");
return s + "jkl";
})
.orElse("done");
System.out.println(r);
これが生成されます実行
String r = Optional.of("mnt") //changed
.map(s -> {
System.out.println("Running map");
return s + "def";
})
.filter(s -> {
System.out.println("First Filter");
return s.equals("abcdef");
})
.map(s -> {
System.out.println("mapping");
return s + "jkl";
})
.orElse("done");
マップを実行します、First Filter、完了
私はいつもmap
だけ前のfilter
に基づいて実行されているので、これはlazy
考えられるであろうと考えました。これはない真で判明:
Optional.of("s").map(String::toUpperCase)
Stream.of("test").map(String::toUpperCase)
Optional
からmap
が実行されます。 Stream
の1つは表示されません。
EDIT
は、ここで他の答えを行くとアップ投票します。これは他のもののために編集されます。
3日間の異議なく...あなたが証明したのは、空の 'Optional'はマッピング関数を評価しないということです。それは「ストリーム・ウェイ」と考える必要はありません。 'HashSet'を考えてみましょう...すべての要素を削除した後、すべての要素を処理するメソッドはno-opsになります。これらの操作が熱心であるか怠惰であるかは証明されません。これは、「オプションの」操作が*怠惰でないという事実によって最もよく説明されています* ... – Holger
も参照してください。http://ideone.com/TJ6p5G – Holger
@Holger私はヒントを持っていました。私はいつも、オプションの 'filter.filter'は、第1のフィルタに基づいて第2のフィルタが評価されないので、遅延としてカウントすると考えました。 – Eugene
マップ*またはフィルタ式に何かを記録して、何時にログに記録するかで簡単に確認できます。 – luk2302
コード行がもっと役立つでしょう:) –
いいえ、最も役立つのは、あなたが自分自身で理解することです。あなたが最も学ぶ方法です。 – luk2302