目录
1. 异常的概念
- Java 异常是一个描述在代码段中发生异常的对象,当发生异常情况时,一个代表该异常的对象被创建并且在导致该异常的方法中被抛出,而该方法可以选择自己处理异常或者传递该异常。
2. 异常继承体系
Throwable 可以用来表示任何可以作为异常抛出的类,分为两种: Error 和 Exception
- Error:通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些错误时,建议终止程序;
- Exception:通常情况下是可以被程序处理的,捕获后可能恢复,并且在程序中应该尽可能地去处理这些异常。
Java 异常分为两种:
- 受检异常:除了 RuntimeException 及其子类以外,其他的 Exception 类及其子类都属于这种异常。
- 非受检异常:包括 RuntimeException 及其子类和 Error。
注意:非受检查异常为编译器不要求强制处理的异常,受检异常则是编译器要求必须处置的异常。
Exception 这类异常分为运行时异常和非运行时异常(编译异常): - 运行时异常 :包括 RuntimeException 及其子类。比如 NullPointerException、IndexOutOfBoundsException。属于非受检异常,可以进行捕捉处理,也可以不处理。
- 非运行时异常(编译异常):RuntimeExcaption 以外的 Exception。IOException、SQLException 已经自定义的异常,必须要进行处理。
3. Java 异常的处理机制
Java 异常处理机制本质上就是抛出异常和捕捉异常。
3.1 抛出异常
- 抛出异常
在Java中有两种抛出异常的方式,一种是throw,直接抛出异常,另一种是throws,间接抛出异常。
// 例子
public void eat() throws Exception {
throw new Exception();
}
throws exception 在方法声明中使用,表示该方法可能产生此异常,如果在方法声明处使用了throws声明异常,该方法产生异常也不必捕获,直接把异常抛出到调用该方法的地方。如果方法有调用者,那就交给调用者处理,如果调用者继续一层层抛出,那最终交给虚拟机jvm,然后程序会中断.
3.2 捕获异常
- 捕获异常
Java中提供了try-catch和try-catch-finally处理异常结构进行异常捕获和处理,把可能出现异常的代码放入到try语句块中,并使用catch语句块捕获异常。
// 例子1
public void eat() {
try {
sleep();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
// 例子2
public void eat() {
try {
sleep();
} catch (IOException e) {
System.out.println(e.getMessage());
}finally {
}
}
try-catch语句块的执行流程比较简单,首先执行的是try语句块中的语句,这时可能出现以下3种情况:
- 如果try语句块中所有语句正常执行完毕,没有发生异常,那么catch语句块中的所语句都将会被忽略。
- 如果try语句块在执行过程中发生异常,并且这个异常与catch语句块中声明的异常类型匹配,那么try语句块中剩下的代码都将被忽略,而相应的catch语句将会被执行。匹配是指catch所处理的异常类型与所生成的异常类型完全一致或是它的父类。
- 如果try语句块在执行过程中发生异常,而抛出的异常在catch语句块中没有被声明,那么方法立刻退出。
使用try-catch-finally处理异常:
如果希望try语句块中不管是否发生异常,都执行某些代码,那么就需要在try-catch语句块中加入finally语句块,把要执行的语句放入finally语句块中 ,无论是否发生异常finally语句块中的代码总能被执行。
try-catch-finally语句块的执行流程大致分为以下两种情况:
- 如果try语句块中所有语句正常执行,finally语句块也会被执行。catch语句块中的代码不会被执行。
- 如果try语句块在执行过程中发生异常,无论这种异常能否被catch语句块捕获到,都将执行finally语句块中的代码。
注意:try-catch-finally结构中的try语句是必须存在的,catch、finally语句为可选,但是两者至少出现其中之一。 如果在try语句块或者catch语句块中存在return语句,finally语句块中的语句也会执行。发生异常时的执行顺序是,先执行catch语句块中return之前的语句,再执行finally语句块中的语句,最后执行catch语句块中的return语句退出。
4. Java 异常的处理原则
- 具体明确:抛出的异常应能通过异常类名和message准确说明异常的类型和产生异常的原因
- 提早抛出:应尽可能早地发现并抛出异常,便于精确定位问题;
- 延迟捕获:异常的捕获和处理应尽可能延迟,让掌握更多信息的作用域来处理异常
5. Java 常见异常以及错误
6. try-catch-finally语句块的执行
(1) try 块:用于捕获异常。其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块。
(2) catch 块:用于处理try捕获到的异常。
(3) finally 块:无论是否捕获或处理异常,finally 块里的语句都会被执行。 当在 try 块或 catch 块中遇到 return 语句时,finally 语句块将在方法返回之前被执行。
在以下 4 种特殊情况下,finally 语句块不会被执行:
- 在finally语句块中发生了异常
- 在前面的代码中用了System.exit()退出程序。
- 程序所在的线程死亡。
- 关闭 CPU。
7. try-with-resources
适用范围:任何实现 java.lang.AutoCloseable 或者 java.io.Closeable 的对象。
在 try-with-resources 语句中,任何 catch 或 finally 代码块在声明的资源关闭后运行。
使用 try-catch-finally 关闭资源:
// 读取文本文件的内容
Scanner scanner = null;
try {
scanner = new Scanner(new File("D://read.txt"));
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (scanner != null) {
scanner.close();
}
}
使用 try-with-resources 语句改造上面的代码:
try (Scanner scanner = new Scanner(new File("test.txt"))) {
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
使用 try-with-resources 语句关闭多个资源:
try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(new File("test.txt"))); // 这里采用 ";" 进行分割
BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")))) {
int b;
while ((b = bin.read()) != -1) {
bout.write(b);
}
}
catch (IOException e) {
e.printStackTrace();
}