當第一個元素為空時處理 findFirst() 中的 NullPointerException
1. 概述
在這個簡短的教學中,我們將探索在使用findFirst()
方法時避免NullPointerException
的不同方法。
首先,我們將解釋導致該方法因NullPointerException
失敗的原因。然後,我們將使用實際範例演示如何重現和修復異常。
2. 解釋問題
簡而言之,拋出NullPointerException來表示我們正在需要物件的地方使用null
進行某些操作。
通常,我們使用findFirst()
傳回一個包含給定流的第一個元素的Optional
實例。但是,根據文檔,如果第一個傳回的元素為null
,則該方法將拋出NullPointerException 。
因此,這裡的主要問題是當流的第一個元素為null
時如何避免NullPointerException異常。在深入探討並回答我們的問題之前,讓我們先重現這個異常。
3. 重現NullPointerException
例如,假設我們有一個String
物件列表:
List<String> inputs = Arrays.asList(null, "foo", "bar");
現在,讓我們嘗試使用findFirst()
方法來取得清單的第一個元素:
@Test(expected = NullPointerException.class)
public void givenStream_whenCallingFindFirst_thenThrowNullPointerException() {
Optional<String> firstElement = inputs.stream()
.findFirst();
}
正如我們所看到的,測試案例因NullPointerException失敗,因為清單中第一個選定的元素為null
。
Optional
API 聲明呼叫者有責任確保該值不為null
,因為它沒有提供任何方法來區分“該值存在但設置為null
”和“該值不存在” 。這就是為什麼文件禁止使用findFirst()
時傳回null
情況。
4. 避免異常
在這種情況下,避免NullPointerException 的最簡單方法是在呼叫findFirst()
方法之前filter
流。
那麼,讓我們看看如何在實踐中做到這一點:
@Test
public void givenStream_whenUsingFilterBeforeFindFirst_thenCorrect() {
Optional<String> firstNotNullElement = inputs.stream()
.filter(Objects::nonNull)
.findFirst();
assertTrue(firstNotNullElement.isPresent());
}
在這裡,我們使用Objects#nonNull
方法僅過濾不為null
物件。這樣,我們確保所選的第一個元素不為null
。因此,我們避免了NullPointerException 。
另一個選擇是在呼叫findFirst()
方法之前使用Optional#ofNullable
方法。
如果指定值不為null
,則此方法傳回一個具有指定值的Optional
實例。否則,它會傳回一個空的Optional
。
那麼,讓我們看看它的實際效果:
@Test
public void givenStream_whenUsingOfNullableBeforeFindFirst_thenCorrect() {
Optional<String> firstElement = inputs.stream()
.map(Optional::ofNullable)
.findFirst()
.flatMap(Function.identity());
assertTrue(firstElement.isEmpty());
}
如上所示,我們藉助ofNullable()
方法將每個元素對應到一個接受null
Optional
物件。然後,我們使用findFirst()
來取得第一個映射元素。
傳回的元素表示Optional
的Optional
,因為findFirst()
傳回一個Optional
。這就是為什麼我們使用flapMap()
來展平巢狀的Optional
。
請注意, Function#identity
始終傳回其輸入參數。在我們的例子中,該方法傳回null
因為它是列表的第一個元素。
5. 結論
在這篇簡短的文章中,我們解釋瞭如何在使用findFirst()
方法時避免NullPointerException
。
在此過程中,我們展示瞭如何使用實際範例重現和解決異常。
與往常一樣,範例的完整原始程式碼可在 GitHub 上取得。