Clojure 异常处理

2018-12-23 18:06 更新

在任何编程语言中都需要异常处理来处理运行时错误,从而可以保持应用程序的正常流程。 异常通常会破坏应用程序的正常流程,这就是为什么我们需要在我们的应用程序中使用异常处理的原因。

异常大致分为以下几类:

  • 检查异常 - 扩展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

错误

错误是无法恢复的,比如: OutOfMemoryErrorVirtualMachineErrorAssertionError等。这些是程序永远不能恢复的错误,并将导致程序崩溃。 我们现在需要一些机制来捕获这些异常,以便如果这些异常存在,程序可以继续运行。

下图显示了如何组织Clojure中的异常层次结构。 它都基于Java中定义的层次结构。

Clojure中的例外

捕捉异常

就像其他编程语言一样,Clojure提供了正常的“try-catch”块来捕获异常。

下面是Clojure 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”捕获的。

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

从上面的程序,你可以看到最后的块也实现后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

以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号