當第一個元素為空時處理 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 上取得。