Clojure 異常處理

2018-12-23 18:06 更新

在任何編程語言中都需要異常處理來處理運(yùn)行時(shí)錯(cuò)誤,從而可以保持應(yīng)用程序的正常流程。 異常通常會(huì)破壞應(yīng)用程序的正常流程,這就是為什么我們需要在我們的應(yīng)用程序中使用異常處理的原因。

異常大致分為以下幾類:

  • 檢查異常 - 擴(kuò)展Throwable類(除了RuntimeException和Error)的類稱為檢查異常。 例如。 IOException,SQLException等。檢查的異常在編譯時(shí)檢查。

讓我們考慮下面的程序?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的類稱為未檢查異常。 例如,ArithmeticException,NullPointerException,ArrayIndexOutOfBoundsException等。未檢查的異常不在編譯時(shí)檢查,而是在運(yùn)行時(shí)檢查。

一個(gè)典型的情況是ArrayIndexOutOfBoundsException,當(dāng)您嘗試訪問大于數(shù)組長度的數(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ò)誤

錯(cuò)誤是無法恢復(fù)的,比如: OutOfMemoryError,VirtualMachineError,AssertionError等。這些是程序永遠(yuǎn)不能恢復(fù)的錯(cuò)誤,并將導(dǎo)致程序崩潰。 我們現(xiàn)在需要一些機(jī)制來捕獲這些異常,以便如果這些異常存在,程序可以繼續(xù)運(yùn)行。

下圖顯示了如何組織Clojure中的異常層次結(jié)構(gòu)。 它都基于Java中定義的層次結(jié)構(gòu)。

Clojure中的例外

捕捉異常

就像其他編程語言一樣,Clojure提供了正常的“try-catch”塊來捕獲異常。

下面是Clojure try-catch語法。

(try
   (//Protected code)
   catch Exception e1)
(//Catch block)

所有可能引發(fā)異常的代碼都放在受保護(hù)的代碼塊中。

在catch塊中,您可以編寫自定義代碼來處理異常,以便應(yīng)用程序可以從異常中恢復(fù)。

讓我們看看我們之前的例子,它生成了一個(gè)未找到文件的異常,看看我們?nèi)绾问褂胻ry catch塊來捕獲程序引發(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)

從上面的代碼,我們在try塊中包裝錯(cuò)誤的代碼。 在catch塊中,我們只是捕獲我們的異常并輸出一個(gè)異常已經(jīng)發(fā)生的消息。 因此,我們現(xiàn)在有一個(gè)有意義的捕獲異常的方法,它是由程序生成的。

多個(gè)catch塊

可以有多個(gè)catch塊來處理多種類型的異常。 對于每個(gè)catch塊,根據(jù)引發(fā)的異常的類型,您將編寫代碼來相應(yīng)地處理它。

讓我們修改我們早期的代碼,以包含兩個(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塊

finally塊跟在try塊或catch塊之后。 代碼的finally塊總是執(zhí)行,而不管異常的發(fā)生。

使用finally塊可以運(yùn)行任何你想要執(zhí)行的清除類型語句,無論在受保護(hù)代碼中發(fā)生什么。 以下是此塊的語法。

(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類似,因此在Clojure中也可以使用以下方法來管理異常:

  • public String getMessage() -返回有關(guān)已發(fā)生異常的詳細(xì)消息。 此消息在Throwable構(gòu)造函數(shù)中初始化。

  • public Throwable getCause() -返回由Throwable對象表示的異常原因。

  • public String toString() -返回與getMessage()的結(jié)果連接的類的名稱。

  • 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對象的堆棧跟蹤,添加到堆棧跟蹤中的任何以前的信息。

以下是使用上面列出的一些方法的示例代碼。

(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

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號