目录
1、什么是异常?
2、捕获并处理异常
try-with-resources 语句
3、通过方法抛出异常
自定义异常
1、什么是异常?
定义:异常是在程序执行过程中发生的一种事件,它会中断程序指令的正常流程。
当方法中发生错误时,该方法会创建一个对象并将其移交给运行时系统。该对象称为异常对象,包含有关错误的一些信息,比如错误的类型和错误发生时程序的状态等。创建异常对象并将其交给运行时系统的行为称为抛出异常。
方法抛出异常后,运行时系统会尝试寻找处理异常的方法。这些处理异常的方法可能是一个有序的方法集合,通过调用这些方法来获取错误抛出的位置。方法调用堆栈如下:
运行时系统会在调用堆栈中搜索可以处理该异常的方法(代码块),该代码块称为异常处理程序。搜索从发生错误的方法开始,然后按照与调用方法的相反顺序遍历调用堆栈,如果找到了适当的处理程序,运行时系统会将异常传递给处理程序。如果程序没有找到能处理该异常的代码块,那么程序将终止运行。
Java 有三种类型的异常:编译时异常、运行时异常、错误(Error)。
在 Java 中处理异常的两种方式:
- 使用捕获异常的 try 语句// try...catch...finally
- 指定一个方法可以抛出的异常。该方法必须提供一个throws子句来列出异常。
2、捕获并处理异常
try-with-resources 语句
在关闭文件或以其他方式恢复资源时,推荐使用 try-with-resources 语句而不是finally块。try-with-resources 语句在不再需要系统资源时会自动释放系统资源。// 关闭或者恢复资源
public void writeList() throws IOException {
try (FileWriter f = new FileWriter("OutFile.txt");
PrintWriter out = new PrintWriter(f)) {
for (int i = 0; i < SIZE; i++) {
out.println("Value at: " + i + " = " + list.get(i));
}
}
}
try-with-resources 语句是一个 try 语句,在该语句中可以声明一个或多个资源。资源是程序使用完后必须关闭的对象。try-with-resources 语句可以确保在语句末尾关闭每个资源。任何实现了java.lang.AutoCloseable 或 java.io.Closeable 接口的对象,都可作为 try-with-resources 的资源使用。
注意:try-with-resources 语句可以像普通的 try 语句一样有 catch 和 finally 块。catch 或 finally 语句块会在声明的资源被关闭后运行。
不使用 try-with-resources 语句关闭资源带来的资源泄露问题:
在 Java SE 7之前,可以使用 finally 块来关闭资源。下面的例子使用 finally 块代替 try-with-resources 语句:
static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {
FileReader fr = new FileReader(path);
BufferedReader br = new BufferedReader(fr);
try {
return br.readLine();
} finally {
br.close(); // 此关闭方式存在资源泄露问题
fr.close();
}
}
但是,上例可能存在资源泄漏问题。上边程序在完成资源使用后,除了依赖垃圾收集器(GC)回收内存资源外,还需要通过调用资源的 close 方法,将资源释放回给操作系统。但是,如果程序在GC回收资源之前没有释放资源,那么释放资源所需的信息就会丢失。该资源仍被认为操作系统正在使用,所以会出现资源泄漏的问题。
在本例中,如果 readLine 方法抛出异常,并且 finally 块中的 br.close() 语句抛出异常,那么FileReader已经泄漏。因此,推荐使用 try-with-resources 语句而不是 finally 块来关闭程序的资源。
3、通过方法抛出异常
在一些情况下,异常发生时,通过代码捕获异常是合适的。然而,在一些情况下,让调用堆栈上的方法去处理异常可能更加合适。例如,异常发生时,你无法预测到所有用户的需求。那么在这种情况下,就最好不捕获异常,并允许调用堆栈上的方法去处理它。// 直接抛出异常
Throwable Class 和它的子类:
Error Class:当 Java 虚拟机中发生动态链接故障或其他故障时,虚拟机抛出一个 Error。简单的程序通常不会捕获或抛出 Error。
Exception Class:大多数程序抛出和捕获派生自 Exception Class 的对象。Exception 表示发生了问题,但不是严重的系统问题。我们编写的大多数程序都会抛出和捕获 Exception,而不是 Error。
自定义异常
继承 Exception,可以实现自定义异常。
关于运行时异常(未检查异常):
运行时异常可以发生在程序中的任何地方,典型的运行时异常可能非常多。如果必须在每个方法声明中添加运行时异常会降低程序的清晰度。因此,编译器不要求你捕获或指定运行时异常(尽管您可以)。
一般来说,不要抛出 RuntimeException 或创建 RuntimeException 的子类,因为你不想为指定方法可以抛出的异常而烦恼。
下面是底线准则:如果客户端可以合理地从异常中恢复,那么将其设置为检查异常。如果客户端无法从异常中恢复,则将其设置为未检查异常。
// 异常是 Java 中比较简单的一部分,该处只对异常做了一些简单的记录,以上一些表述摘自一些官方的介绍,供日常学习和知识梳理。