2015-04-02 75 views
16

在獲取流之前做空檢查的最佳/習慣用法是什麼?如何從可空對象中最好地創建Java 8流?

我有方法接收List可能爲空。所以我不能只傳遞.stream()就可以了。有沒有一些靜態助手會給我一個空的流,如果一個值爲空?

+2

我強烈建議在列表提供方的工作。 optionals的全部目的是不處理'null'引用。如果一個方法返回一個可能爲'null'的列表,它應該返回一個可選的。如果這是不可能的,你可以把它包裝成可選的(根據答案)。另外,你想用這個列表做一些事情,也就是說,如果它存在,你就要消費它。因此,只需在其上調用['Optional.ifPresent'](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#ifPresent-java.util.function.Consumer-) 。 – Seelenvirtuose 2015-04-02 07:09:57

回答

27

Stuart Marks同意list == null ? Stream.empty() : list.stream()是要做到這一點(見his answer)的最好辦法,或者至少做到這一點的最好辦法在Java 9之前(請參閱下面的編輯),但我會留下這個答案來演示可選API的用法。

<T> Stream<T> getStream(List<T> list) { 
    return Optional.ofNullable(list).map(List::stream).orElseGet(Stream::empty); 
} 

編輯:爪哇9用參數作爲其唯一的元素添加的靜態方法Stream.<T>ofNullable(T),它返回給定null參數空流,否則流。如果參數是一個集合,我們可以用flatMap將它變成一個流。

<T> Stream<T> fromNullableCollection(Collection<? extends T> collection) { 
    return Stream.ofNullable(collection).flatMap(Collection::stream); 
} 

這不濫用可選API由斯圖爾特·馬克斯的討論,並在對比的是三元運算解決方案,還有一個空指針異常沒有機會(比如,如果你不重視和搞砸了操作數的順序)。它也可以與上界通配符一起使用,不需要SuppressWarnings("unchecked"),這要歸功於flatMap的簽名,因此您可以從T的任何子類型的元素集合中獲得Stream<T>

+0

我喜歡這個助手的例子,我可以重用一堆,並避免在我的代碼中散佈'Optional.orNullable'。 – checketts 2015-04-02 06:59:38

+3

在List :: stream中不需要明確的類型參數'';它沒有工作。而'.orElse(Stream.empty())'可以被'.orElseGet(Stream :: empty)'替代,這樣稍微有效一些,因爲它避免了構造一個空的流。 – Holger 2015-04-02 10:17:41

+0

@Holger,我做了這些改變,但我想知道什麼'Stream :: empty'實際上在幕後產生。一個匿名課程? – gdejohn 2015-04-02 11:05:59

7

我能想到的最好的方法是使用OptionalorElseGet方法。

return Optional.ofNullable(userList) 
       .orElseGet(Collections::emptyList) 
       .stream() 
       .map(user -> user.getName()) 
       .collect(toList()); 

更新與@ Misha的建議使用Collections::emptyListArrayList::new

+4

最好使用'Collections :: emptyList'而不是'ArrayList :: new'。它使意圖更清楚,並且(稍微)更高效。 – Misha 2015-04-02 06:43:25

10

在其他答案中,Optional實例是嚴格在同一個語句中創建和使用的。 Optional類主要用於communicating with the caller關於存在還是不存在返回值,如果存在,則與實際值融合。完全在單一方法中使用它似乎沒有必要。

讓我提出以下建議較爲平淡的技術:

static <T> Stream<T> nullableListToStream(List<T> list) { 
    return list == null ? Stream.empty() : list.stream(); 
} 

我猜三元運算符是有點家世不那麼高貴,這些天,但我認爲這是最簡單和最有效的解決方案。

如果我真的寫了這個(也就是說,對於一個真正的庫,不僅僅是堆棧溢出的示例代碼),我會放入通配符,以便流返回類型可以不同於List類型。哦,它可以是一個集合,因爲這是在哪裏定義的stream()方法:

@SuppressWarnings("unchecked") 
static <T> Stream<T> nullableCollectionToStream(Collection<? extends T> coll) { 
    return coll == null ? Stream.empty() : (Stream<T>)coll.stream(); 
} 

(警告抑制是因爲從Stream<? extends T>投給Stream<T>這是安全的必要,但是編譯器不知道那。)

5

阿帕奇公地collections4:

CollectionUtils.emptyIfNull(list).stream() 
+0

嗨piotrek;你的代碼可能是正確的,但在某些情況下會更好;例如,您可以解釋如何以及爲什麼這個提議的變更可以解決提問者的問題,或許還包括指向相關文檔的鏈接。這將使它對他們更有用,而且對尋求類似問題解決方案的其他網站讀者也更有用。 – 2016-08-17 09:36:50

+0

不確定應該說明什麼。 apache commons-collections是最標準的java庫之一。它如何解決OP問題?它直接做OP所需要的 - 它從一個可爲空的列表中產生一個流 – piotrek 2016-08-17 17:09:59

0

我個人考慮零廢棄,使用可選儘可能儘管(微小)的性能開銷。所以我使用Stuart Marks的接口和基於gdejohn的實現,即

@SuppressWarnings("unchecked") 
static <T> Stream<T> nullableCollectionToStream(Collection<? extends T> coll) 
{ 
    return (Stream<T>) Optional.ofNullable(coll) 
          .map(Collection::stream) 
          .orElseGet(Stream::empty); 
}