
- Clojure 教程
- Clojure - 首頁
- Clojure - 概述
- Clojure - 環境
- Clojure - 基本語法
- Clojure - REPL
- Clojure - 資料型別
- Clojure - 變數
- Clojure - 運算子
- Clojure - 迴圈
- Clojure - 決策
- Clojure - 函式
- Clojure - 數字
- Clojure - 遞迴
- Clojure - 檔案 I/O
- Clojure - 字串
- Clojure - 列表
- Clojure - 集合
- Clojure - 向量
- Clojure - 對映
- Clojure - 名稱空間
- Clojure - 異常處理
- Clojure - 序列
- Clojure - 正則表示式
- Clojure - 斷言
- Clojure - 解構
- Clojure - 日期和時間
- Clojure - 原子
- Clojure - 元資料
- Clojure - StructMaps
- Clojure - 代理
- Clojure - 觀察者
- Clojure - 宏
- Clojure - 引用值
- Clojure - 資料庫
- Clojure - Java 介面
- Clojure - 併發程式設計
- Clojure - 應用
- Clojure - 自動化測試
- Clojure - 庫
- Clojure 有用資源
- Clojure - 快速指南
- Clojure - 有用資源
- Clojure - 討論
Clojure - 異常處理
任何程式語言都需要異常處理來處理執行時錯誤,以便維護應用程式的正常流程。異常通常會中斷應用程式的正常流程,這就是為什麼我們需要在應用程式中使用異常處理的原因。
異常大致可分為以下幾類:
受檢異常 - 擴充套件 Throwable 類(除了 RuntimeException 和 Error)的類稱為受檢異常。例如 IOException、SQLException 等。受檢異常在編譯時進行檢查。
讓我們考慮以下程式,它對名為 Example.txt 的檔案執行操作。但是,始終可能存在 Example.txt 檔案不存在的情況。
(ns clojure.examples.example (:gen-class)) ;; This program displays Hello World (defn Example [] (def string1 (slurp "Example.txt")) (println string1)) (Example)
如果 Example.txt 檔案不存在,則程式將生成以下異常。
Caused by: java.io.FileNotFoundException: Example.txt (No such file or directory) at java.io.FileInputStream.open0(Native Method) at java.io.FileInputStream.open(FileInputStream.java:195) at java.io.FileInputStream.<init>(FileInputStream.java:138) at clojure.java.io$fn__9185.invoke(io.clj:229) at clojure.java.io$fn__9098$G__9091__9105.invoke(io.clj:69) at clojure.java.io$fn__9197.invoke(io.clj:258) at clojure.java.io$fn__9098$G__9091__9105.invoke(io.clj:69)
從上面的異常中,我們可以清楚地看到程式引發了 FileNotFoundException。
非受檢異常 - 擴充套件 RuntimeException 的類稱為非受檢異常。例如,ArithmeticException、NullPointerException、ArrayIndexOutOfBoundsException 等。非受檢異常在編譯時不進行檢查,而是在執行時檢查。
一個經典的例子是 ArrayIndexOutOfBoundsException,當您嘗試訪問陣列索引時,該索引大於陣列的長度。以下是此類錯誤的典型示例。
(ns clojure.examples.example (:gen-class)) (defn Example [] (try (aget (int-array [1 2 3]) 5) (catch Exception e (println (str "caught exception: " (.toString e)))) (finally (println "This is our final block"))) (println "Let's move on")) (Example)
執行上述程式碼時,將引發以下異常。
caught exception: java.lang.ArrayIndexOutOfBoundsException: 5 This is our final block Let's move on
錯誤
錯誤是不可恢復的,例如 OutOfMemoryError、VirtualMachineError、AssertionError 等。這些是程式永遠無法恢復的錯誤,會導致程式崩潰。現在我們需要一些機制來捕獲這些異常,以便程式在存在這些異常時能夠繼續執行。
下圖顯示了 Clojure 中異常的層次結構是如何組織的。它全部基於 Java 中定義的層次結構。

捕獲異常
與其他程式語言一樣,Clojure 提供了正常的“try-catch”塊來捕獲異常的發生。
以下是 try-catch 塊的一般語法。
(try (//Protected code) catch Exception e1) (//Catch block)
所有可能引發異常的程式碼都放置在受保護的程式碼塊中。
在catch 塊中,您可以編寫自定義程式碼來處理異常,以便應用程式能夠從異常中恢復。
讓我們看看我們之前的示例,該示例生成了檔案未找到異常,並瞭解如何使用 try catch 塊來捕獲程式引發的異常。
(ns clojure.examples.example (:gen-class)) (defn Example [] (try (def string1 (slurp "Example.txt")) (println string1) (catch Exception e (println (str "caught exception: " (.getMessage e)))))) (Example)
上述程式產生以下輸出。
caught exception: Example.txt (No such file or directory)
從上面的程式碼中,我們將有問題的程式碼包裝在try 塊中。在 catch 塊中,我們只是捕獲異常並輸出一條訊息,表明發生了異常。因此,我們現在有了一種有意義的方法來捕獲程式生成的異常。
多個 Catch 塊
可以有多個 catch 塊來處理多種型別的異常。對於每個 catch 塊,根據引發的異常型別,您將編寫程式碼來相應地處理它。
讓我們修改我們之前的程式碼,包括兩個 catch 塊,一個特定於我們的檔案未找到異常,另一個是通用異常塊。
(ns clojure.examples.example (:gen-class)) (defn Example [] (try (def string1 (slurp "Example.txt")) (println string1) (catch java.io.FileNotFoundException e (println (str "caught file exception: " (.getMessage e)))) (catch Exception e (println (str "caught exception: " (.getMessage e))))) (println "Let's move on")) (Example)
上述程式產生以下輸出。
caught file exception: Example.txt (No such file or directory) Let's move on
從上面的輸出中,我們可以清楚地看到我們的異常被“FileNotFoundException”catch 塊捕獲,而不是通用 catch 塊。
Finally 塊
finally 塊位於 try 塊或 catch 塊之後。finally 程式碼塊始終執行,無論是否發生異常。
使用 finally 塊允許您執行任何您希望執行的清理型別語句,無論受保護程式碼中發生了什麼。以下是此塊的語法。
(try (//Protected code) catch Exception e1) (//Catch block) (finally //Cleanup code)
讓我們修改上面的程式碼並新增 finally 程式碼塊。以下是程式碼片段。
(ns clojure.examples.example (:gen-class)) (defn Example [] (try (def string1 (slurp "Example.txt")) (println string1) (catch java.io.FileNotFoundException e (println (str "caught file exception: " (.getMessage e)))) (catch Exception e (println (str "caught exception: " (.getMessage e)))) (finally (println "This is our final block"))) (println "Let's move on")) (Example)
上述程式產生以下輸出。
caught file exception: Example.txt (No such file or directory) This is our final block Let's move on
從上面的程式中,您可以看到 finally 塊也在 catch 塊捕獲所需異常之後實現。
由於 Clojure 的異常處理源自 Java,因此與 Java 類似,Clojure 中提供了以下方法來管理異常。
public String getMessage() - 返回有關發生的異常的詳細訊息。此訊息在 Throwable 建構函式中初始化。
public Throwable getCause() - 返回異常的原因,表示為 Throwable 物件。
public String toString() - 返回類的名稱與 getMessage() 的結果連線在一起。
public void printStackTrace() - 將 toString() 的結果以及堆疊跟蹤列印到 System.err(錯誤輸出流)。
public StackTraceElement [] getStackTrace() - 返回一個包含堆疊跟蹤中每個元素的陣列。索引 0 處的元素表示呼叫堆疊的頂部,陣列中的最後一個元素表示呼叫堆疊底部的 方法。
public Throwable fillInStackTrace() - 使用當前堆疊跟蹤填充此 Throwable 物件的堆疊跟蹤,新增到堆疊跟蹤中的任何先前資訊。
以下是使用上面列出的一些方法的示例程式碼。
(ns clojure.examples.example (:gen-class)) (defn Example [] (try (def string1 (slurp "Example.txt")) (println string1) (catch java.io.FileNotFoundException e (println (str "caught file exception: " (.toString e)))) (catch Exception e (println (str "caught exception: " (.toString e)))) (finally (println "This is our final block"))) (println "Let's move on")) (Example)
上述程式產生以下輸出。
caught file exception: java.io.FileNotFoundException: Example.txt (No such file or directory) This is our final block Let's move on