如何避免 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 上取得。