在任何編程語(yǔ)言中都需要異常處理來(lái)處理運(yùn)行時(shí)錯(cuò)誤,從而可以保持應(yīng)用程序的正常流程。 異常通常會(huì)破壞應(yīng)用程序的正常流程,這就是為什么我們需要在我們的應(yīng)用程序中使用異常處理的原因。
異常大致分為以下幾類(lèi):
讓我們考慮下面的程序?qū)σ粋€(gè)名為Example.txt的文件進(jìn)行操作。 但是,可能總是有一種情況,其中文件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不存在,則程序?qū)⑸梢韵庐惓!?
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)
從上面的異常,我們可以清楚地看到程序引發(fā)了FileNotFoundException。
未選中的異常 -擴(kuò)展RuntimeException的類(lèi)稱(chēng)為未檢查異常。 例如,ArithmeticException,NullPointerException,ArrayIndexOutOfBoundsException等。未檢查的異常不在編譯時(shí)檢查,而是在運(yùn)行時(shí)檢查。
一個(gè)典型的情況是ArrayIndexOutOfBoundsException,當(dāng)您嘗試訪問(wèn)大于數(shù)組長(zhǎng)度的數(shù)組的索引時(shí),會(huì)發(fā)生這種情況。 以下是這種錯(cuò)誤的典型例子。
(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)
當(dāng)上面的代碼被執(zhí)行時(shí),將引發(fā)以下異常。
caught exception: java.lang.ArrayIndexOutOfBoundsException: 5 This is our final block Let's move on
錯(cuò)誤是無(wú)法恢復(fù)的,比如: OutOfMemoryError,VirtualMachineError,AssertionError等。這些是程序永遠(yuǎn)不能恢復(fù)的錯(cuò)誤,并將導(dǎo)致程序崩潰。 我們現(xiàn)在需要一些機(jī)制來(lái)捕獲這些異常,以便如果這些異常存在,程序可以繼續(xù)運(yùn)行。
下圖顯示了如何組織Clojure中的異常層次結(jié)構(gòu)。 它都基于Java中定義的層次結(jié)構(gòu)。
就像其他編程語(yǔ)言一樣,Clojure提供了正常的“try-catch”塊來(lái)捕獲異常。
下面是Clojure try-catch語(yǔ)法。
(try (//Protected code) catch Exception e1) (//Catch block)
所有可能引發(fā)異常的代碼都放在受保護(hù)的代碼塊中。
在catch塊中,您可以編寫(xiě)自定義代碼來(lái)處理異常,以便應(yīng)用程序可以從異常中恢復(fù)。
讓我們看看我們之前的例子,它生成了一個(gè)未找到文件的異常,看看我們?nèi)绾问褂胻ry catch塊來(lái)捕獲程序引發(fā)的異常。
(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)
以上示例將輸出下面的結(jié)果:
caught exception: Example.txt (No such file or directory)
從上面的代碼,我們?cè)?strong>try塊中包裝錯(cuò)誤的代碼。 在catch塊中,我們只是捕獲我們的異常并輸出一個(gè)異常已經(jīng)發(fā)生的消息。 因此,我們現(xiàn)在有一個(gè)有意義的捕獲異常的方法,它是由程序生成的。
可以有多個(gè)catch塊來(lái)處理多種類(lèi)型的異常。 對(duì)于每個(gè)catch塊,根據(jù)引發(fā)的異常的類(lèi)型,您將編寫(xiě)代碼來(lái)相應(yīng)地處理它。
讓我們修改我們?cè)缙诘拇a,以包含兩個(gè)catch塊,一個(gè)特定于我們的文件未找到異常,另一個(gè)是一個(gè)一般的異常塊。
(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)
以上示例將輸出下面的結(jié)果:
caught file exception: Example.txt (No such file or directory) Let's move on
從上面的輸出,我們可以清楚地看到,我們的異常被“FileNotFoundException”捕獲的。
finally塊跟在try塊或catch塊之后。 代碼的finally塊總是執(zhí)行,而不管異常的發(fā)生。
使用finally塊可以運(yùn)行任何你想要執(zhí)行的清除類(lèi)型語(yǔ)句,無(wú)論在受保護(hù)代碼中發(fā)生什么。 以下是此塊的語(yǔ)法。
(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)
以上示例將輸出下面的結(jié)果:
caught file exception: Example.txt (No such file or directory) This is our final block Let's move on
從上面的程序,你可以看到最后的塊也實(shí)現(xiàn)后catch塊捕獲所需的異常。
由于Clojure從Java中獲取其異常處理,與Java類(lèi)似,因此在Clojure中也可以使用以下方法來(lái)管理異常:
public String getMessage() -返回有關(guān)已發(fā)生異常的詳細(xì)消息。 此消息在Throwable構(gòu)造函數(shù)中初始化。
public Throwable getCause() -返回由Throwable對(duì)象表示的異常原因。
public String toString() -返回與getMessage()的結(jié)果連接的類(lèi)的名稱(chēng)。
public void printStackTrace() -將toString()的結(jié)果與堆棧跟蹤一起打印到System.err,錯(cuò)誤輸出流。
public StackTraceElement [] getStackTrace() -返回包含堆棧跟蹤上的每個(gè)元素的數(shù)組。 索引0處的元素表示調(diào)用堆棧的頂部,數(shù)組中的最后一個(gè)元素表示調(diào)用堆棧底部的方法。
public Throwable fillInStackTrace() -使用當(dāng)前堆棧跟蹤填充此Throwable對(duì)象的堆棧跟蹤,添加到堆棧跟蹤中的任何以前的信息。
以下是使用上面列出的一些方法的示例代碼。
(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)
以上示例將輸出下面的結(jié)果:
caught file exception: java.io.FileNotFoundException: Example.txt (No such file or directory) This is our final block Let's move on
更多建議: