📅  最后修改于: 2020-11-05 04:03:14             🧑  作者: Mango
任何编程语言都需要异常处理来处理运行时错误,以便可以维护应用程序的正常流程。异常通常会中断应用程序的正常流程,这就是为什么我们需要在应用程序中使用异常处理的原因。
例外大致分为以下几类-
检查异常-扩展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.(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块,一个专门针对未找到文件的异常,另一个专门针对一般异常块。
(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块而不是通用块捕获的。
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
从上面的程序中,您可以看到在catch块捕获所需的异常之后,也实现了final块。
由于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