2017-05-26 74 views
1

map()filter()Optional是否像Stream一樣懶?地圖類型()和過濾器()操作的可選

我該如何確認他們的類型?

+1

你可以通過在地圖或過濾器表達式中記錄某些東西,然後檢查什麼時候記錄東西來輕鬆驗證。 – luk2302

+0

一行代碼會更有幫助:) –

+2

不,最有幫助的將是你自己想出來,這樣你學到最多。 – luk2302

回答

2

StreamOptional之間存在根本差異。

A Stream封裝了整個處理管道,在做任何事情之前收集所有操作。這允許實現根據實際請求的結果來選擇不同的處理策略。這也允許在鏈中插入修飾符如unordered()parallel(),因爲到目前爲止還沒有做任何事情,所以我們可以改變後續實際處理的行爲。

一個極端的例子是Stream.of(1, 2, 3).map(function).count(),這將不處理function中的Java 9在所有,作爲3不變結果可以在沒有被確定。

相反,Optional只是一個值(如果不爲空)的包裝。每個操作都將立即執行,以返回封裝新值的新Optional或空的Optional。在Java 8中,返回Optional(即map,flatMapfilter)的所有方法只會在應用於空可選項時返回空可選項,因此在鏈接它們時,空可選項將成爲一種死衚衕。

但是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); 

將打印

starting query 
Running map 
result has value 
result value: abcdef 

表示映射函數沒有在終端操作findAny()開始之前評價。由於我們無法多次查詢數據流,因此使用findAny()甚至使用Optional作爲返回值,這使我們可以用最終結果做到這一點。


同名的操作之間還存在其他語義差異,例如,如果映射函數評估爲null,則Optional.map將返回空的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); 

運行,這將產生:

運行圖,首先篩選,映射運行此abcdefjkl

在另一方面:

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"); 

運行圖,第一個過濾器,完成

我一直以爲,既然是map只執行基於以前filter,這將被視爲lazy。原來,這是不是真的

Optional.of("s").map(String::toUpperCase) 
Stream.of("test").map(String::toUpperCase) 

Optionalmap將得到執行;而從Stream不會。

編輯

去和贊成票這裏的其他答案。這是由於另一個編輯。

+0

三天沒有異議......所有你已經證明的是,一個空的'可選的'不評估映射函數。這不需要被認爲是「流路」。想想一個'HashSet' ...在你刪除所有元素後,處理所有元素的方法變成空操作。這並不能證明這些行動是渴望還是懶惰。這是最好的說明'可選'操作是*不懶惰* – Holger

+0

也請參見http://ideone.com/TJ6p5G – Holger

+0

@Holger我有一個提示我錯過了什麼,thx回到這裏。我一直認爲可選的'filter.filter'會算作懶惰,因爲第二個過濾器不是基於第一個過濾器進行評估的。 – Eugene