- 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 - 结构映射
- 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。
Unchecked Exception - 扩展 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 块捕获的,而不是一般的异常。
最后阻止
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块捕获到需要的异常之后,finally块也被实现了。
由于 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