如何避免 Stream API 中的 NoSuchElementException
1. 概述
在這個簡短的教學中,我們將說明如何在使用 Stream API 時避免NoSuchElementException
。
首先,我們要解釋一下異常的主要原因。然後,我們將使用實際範例展示如何重現和修復它。
2. 異常原因
在深入研究細節之前,讓我們先了解一下異常的含義。
簡而言之,拋出NoSuchElementException
來表示所要求的元素不存在。例如,嘗試存取不可用或不存在的元素將導致此異常。
通常,在使用 Stream API 時,對空的Optional
實例呼叫get()
方法是導致NoSuchElementException
最常見的原因之一。
3. 產生異常
現在我們知道了異常是什麼,讓我們深入研究如何在實踐中重現它。
例如,讓我們建立一個名稱清單並使用 Stream API 對其進行篩選:
@Test(expected = NoSuchElementException.class)
public void givenEmptyOptional_whenCallingGetMethod_thenThrowNoSuchElementException() {
List<String> names = List.of("William", "Amelia", "Albert", "Philip");
Optional<String> emptyOptional = names.stream()
.filter(name -> name.equals("Emma"))
.findFirst();
emptyOptional.get();
}
正如我們所看到的,我們使用filter()
方法來尋找名稱“Emma”
。此外,我們與findFirst()
方法連結以取得包含第一個找到的元素的Optional
,或者如果過濾後的流為空,則取得空Optional
。
在這裡,我們的清單不包含名稱“Emma”
,因此findFirst()
傳回一個空的Optional
。測試案例失敗並出現NoSuchElementException
異常,因為我們試圖取得不存在的名稱,且空的Optional
不包含任何值。
4. 避免異常
現在,讓我們看看如何修復該異常。最簡單的方法是在呼叫get()
方法之前檢查Optional
實例中是否存在值。
幸運的是,Stream API 專門為此目的提供了isPresent()
方法。那麼,讓我們看看它的實際效果:
@Test
public void givenEmptyOptional_whenUsingIsPresentMethod_thenReturnDefault() {
List<String> names = List.of("Tyler", "Amelia", "James", "Emma");
Optional<String> emptyOptional = names.stream()
.filter(name -> name.equals("Lucas"))
.findFirst();
String name = "unknown";
if (emptyOptional.isPresent()) {
name = emptyOptional.get();
}
assertEquals("unknown", name);
}
在這裡,我們使用isPresent()
來確保在呼叫get()
方法之前我們的Optional
實例中有一個值。這樣,我們就可以避免NoSuchElementException
異常。
請注意,使用isPresent()
會帶來 if-else 語句的成本。那麼,我們能做得更好嗎?是的!
通常,最好的方法是使用orElse()
方法。簡而言之,此方法傳回值(如果存在),否則傳回給定的後備參數:
@Test
public void givenEmptyOptional_whenUsingOrElseMethod_thenReturnDefault() {
List<String> names = List.of("Nicholas", "Justin", "James");
Optional<String> emptyOptional = names.stream()
.filter(name -> name.equals("Lucas"))
.findFirst();
String name = emptyOptional.orElse("unknown");
assertEquals("unknown", name);
}
如上所示,此方法提供了一種更方便、更直接的方法來避免NoSuchElementException
。
或者,我們可以使用orElseGet()
方法來實現相同的結果:
@Test
public void givenEmptyOptional_whenUsingOrElseGetMethod_thenReturnDefault() {
List<String> names = List.of("Thomas", "Catherine", "David", "Olivia");
Optional<String> emptyOptional = names.stream()
.filter(name -> name.equals("Liam"))
.findFirst();
String name = emptyOptional.orElseGet(() -> "unknown");
assertEquals("unknown", name);
}
與orElse()
不同, orElseGet()
接受供應商作為參數。另一個關鍵差異是orElse()
在所有情況下都會執行,即使Optional
實例有值也是如此。然而, orElseGet()
僅當Optional
值不存在時才執行。
請注意,我們關於orElse()
和orElseGet()
方法之間的差異的文章很好地涵蓋了這個主題。
5. 避免NoSuchElementException
最佳實踐
簡而言之,在使用 Stream API 以避免NoSuchElementException
異常時需要記住幾個關鍵點:
- 在呼叫
get()
方法之前,請務必檢查傳回的流/可選是否不為空。 - 嘗試使用
orElse()
或orElseGet().
- 在流上調用任何終端操作之前使用過濾器。
六,結論
在這篇簡短的文章中,我們探討了在使用 Stream API 時避免例外NoSuchElementException
的不同方法。
在此過程中,我們透過實際範例說明如何重現異常以及如何避免異常。
與往常一樣,範例的完整原始程式碼可在 GitHub 上取得。