## Exception Handling 現代語言以「預先認定」某些程式片段(或執行某特定方法)可能出現 Exception-例外,若事先因為認定其會發生例外,就要求在設計過程中一定要將處理例外情形的程式碼預先撰寫設計好,當執行過程中真的產生例外時,會按照事先設計的程式碼來處理例外,程式也能正常的繼續執行。 ## 例外區塊 Java 語言使用 try…catch 的區塊做為例外處理的機制, try 區塊用來監控==預先認定會出現例外==的程式碼, catch 區塊則是用來放置當例外真的在 try 區塊出現時,所設計並處理例外的程式碼: ![](https://hackmd.io/_uploads/rJV-fWC22.png) 例如使用 FileReader 類別讀取一個檔案時,檔案有可能因為不存在或檔案系統出問題而出現例外,所以得要使用 try…catch 區塊來預先處理例外的發生,如下列範例程式碼: 當 try 區塊中有多行程式時,當某行程式在執行時出現例外,將忽略後續的程式碼而跳至例外的專屬 catch 區塊去執行,執行完成後將往後執行 catch 區塊後的一般程式碼,執行順序如下圖: ![](https://hackmd.io/_uploads/HkE9GZRhn.png)  若 try 區塊內的程式碼,有可能出現一種以上的例外,可以重覆 catch 區塊,以處理不同種類的例外: ![](https://hackmd.io/_uploads/ByScfZA33.png) 在 try…catch 區塊使用時,有時會在最後加上 finally 區塊,不論在 try 區塊內的程式碼是否有出現例外,或是出現例外跳至 catch 區塊執行,finally 區塊內的程式碼都會被執行。一般在開發程式時,會在 finally 區塊中撰寫如關閉檔案或串流物件的程式碼,目的是清理資源 ![](https://hackmd.io/_uploads/SkKcz-A3h.png) ## 往上層拋出例外 當例外出現時也可以選擇當例外出現時不處理,而讓例外往上層呼叫來源拋出,最後如果都沒有處理這個例外,則會在執行過程中被 Java 虛擬機器抓到,而中斷程式的執行。Java使用 throws 不處理而拋出例外,throws 必需使用在方法的定義時,也就是方法的第一行,用法如下方程式碼所示: 在 Java 中,使用 `throws` 關鍵字來拋出例外。`throws` 關鍵字必須在方法的定義中使用,並列出可能被拋出的所有例外類型。例如,以下方法可以拋出 `IOException` 和 `SQLException` 例外: ```java public void readFile(String fileName) throws IOException, SQLException { // ... } ``` 如果 `readFile()` 方法在讀取檔案時遇到錯誤,則會拋出 `IOException` 例外。如果 `readFile()` 方法在連接到資料庫時遇到錯誤,則會拋出 `SQLException` 例外。 呼叫 `readFile()` 方法的程式碼必須使用 `try-catch` 語句來捕獲並處理任何被拋出的例外。例如,以下程式碼會嘗試讀取檔案,並在發生錯誤時處理例外: ```java try { readFile("my-file.txt"); } catch (IOException e) { // Handle the IOException } catch (SQLException e) { // Handle the SQLException } ``` 如果 `readFile()` 方法沒有被呼叫者處理,則最終會被 Java 虛擬機器捕獲並終止程式的執行。 --- ### First Snippet: ```java= public static test fromCode(int num) { return Arrays.stream(test.values()) // .filter(e -> e.getCode() == num) // return Stream<test> .findFirst() // Optional<test> .orElseThrow(() -> new IllegalArgumentException()); // runtime exception } ``` ### Second Snippet: ```java= public static test fromCode(int num) throws IllegalArgumentException { return Arrays.stream(test.values()) // .filter(e -> e.getCode() == num) // return Stream<test> .findFirst() // Optional<test> .orElseThrow(() -> new IllegalArgumentException()); // runtime exception } ``` The main difference between the two snippets is the presence of the throws IllegalArgumentException clause in the second snippet. :::success In the second snippet, the presence of "throws IllegalArgumentException" in the method signature indicates that if the orElseThrow call is triggered (when no matching enum value is found), the method will directly throw an IllegalArgumentException without being caught. In this second method, the IllegalArgumentException is thrown directly by the fromCode() method. Consequently, whoever calls the fromCode() method is responsible for handling the exception. This can be done using a try-catch block to catch the exception or by declaring that the calling method also throws IllegalArgumentException. ::: :::info In the first snippet, since there's no "throws" clause in the method signature, any exception thrown by the orElseThrow method ==needs to be managed within the method itself or propagated to the calling code==. The IllegalArgumentException is thrown by the orElseThrow() method, relieving the caller of the fromCode() method from directly handling the exception. This is because the orElseThrow() method automatically throws the exception when the Optional object is empty. ::: In summary, the main difference is in how exceptions are handled between the two snippets. The first snippet requires you to ==handle the exception within the method== if it's thrown, while the second snippet explicitly indicates that the method will throw an IllegalArgumentException and expects the calling code to handle it or let it propagate. |Method |Where is the IllegalArgumentException thrown?| Who handles the exception?| |-|-|-| fromCode(int num)| By the orElseThrow() method |Caller of the fromCode() method does not need to handle the exception.| fromCode(int num) throws IllegalArgumentException| By the fromCode() method itself |Caller of the fromCode() method must handle the exception.|