2017-05-26 11 views
1

map()filter()Optionalは、Streamのように怠惰ですか?マップの種類()とフィルタ()操作のオプション

どのようにタイプを確認できますか?

この実行している一方

abcdefjklマップ、第一のフィルタ、マッピングを実行する:

+1

マップ*またはフィルタ式に何かを記録して、何時にログに記録するかで簡単に確認できます。 – luk2302

+0

コード行がもっと役立つでしょう:) –

+2

いいえ、最も役立つのは、あなたが自分自身で理解することです。あなたが最も学ぶ方法です。 – luk2302

答えて

2

StreamOptionalの間に基本的な違いがあります。

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という値を返すかどうかは関係ありません(そのため、要素が何をするかを知らずに要素を数えることができます)。

3
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

は、ここで他の答えを行くとアップ投票します。これは他のもののために編集されます。

+0

3日間の異議なく...あなたが証明したのは、空の 'Optional'はマッピング関数を評価しないということです。それは「ストリーム・ウェイ」と考える必要はありません。 'HashSet'を考えてみましょう...すべての要素を削除した後、すべての要素を処理するメソッドはno-opsになります。これらの操作が熱心であるか怠惰であるかは証明されません。これは、「オプションの」操作が*怠惰でないという事実によって最もよく説明されています* ... – Holger

+0

も参照してください。http://ideone.com/TJ6p5G – Holger

+0

@Holger私はヒントを持っていました。私はいつも、オプションの 'filter.filter'は、第1のフィルタに基づいて第2のフィルタが評価されないので、遅延としてカウントすると考えました。 – Eugene

関連する問題