Java异常处理
# Java异常处理
# 异常类的层次结构
在 Java 中,所有的异常都有一个共同的祖先 java.lang
包中的 Throwable
类。Throwable
类有两个重要的子类:
- 异常
Exception
:程序本身可以处理的异常,可以通过catch
来进行捕获- 检查性异常
Checked Exception
:必须处理 - 运行时异常
Runtime Exception
:可以不处理
- 检查性异常
- 错误
Error
:属于程序无法处理的错误。
# 检查性异常
Java 代码在编译过程中,如果受检查异常没有被 catch
/throw
处理的话,就没办法通过编译 。
此时运行程序
java: 未报告的异常错误java.lang.InterruptedException; 必须对其进行捕获或声明以便抛出
1
# 运行时异常
Java 代码在编译过程中 ,我们即使不处理运行时异常也可以正常通过编译。
RuntimeException
及其子类都统称为运行时异常,例如:
NullPointerException
:空指针异常NumberFormatException
:字符串转换为数字异常ArrayIndexOutOfBoundsException
:数组越界ClassCastException
:类型转换错误ArithmeticException
:算术错误ConcurrentModificationException
:并发修改异常
# 错误
错误不是异常,而是脱离程序员控制的问题,它们在编译期间检查不到的,当错误发生程序会立刻停止。
「错误」不是「异常」,但是我们经常把「错误」称为「异常」,比如OOM异常,其实指的是OOM错误。
常见错误有:
java.lang.OutOfMemoryError
:内存溢出错误java.lang.StackOverflowError
:栈溢出错误
# Throwable 类常用方法
String getMessage()
: 返回异常发生时的简要描述String toString()
: 返回异常发生时的详细信息String getLocalizedMessage()
: 返回异常对象的本地化信息。使用Throwable
的子类覆盖这个方法,可以生成本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与getMessage()
返回的结果相同void printStackTrace()
: 在控制台上打印Throwable
对象封装的异常信息
# 异常捕获 try-catch-finally
try
块: 用于捕获异常。其后可接零个或多个catch
块,如果没有catch
块,则必须跟一个finally
块。catch
块: 用于处理 try 捕获到的异常,可以有多个catch
块,每个块用于捕获不同的异常。finally
块: 无论是否捕获或处理异常,finally
块里的语句都会被执行。当在try
块或catch
块中遇到return
语句时,finally
语句块将在方法返回之前被执行。
# try-catch-finally执行顺序
示例:
try {
System.out.println("Try to do something");
throw new RuntimeException("RuntimeException");
} catch (Exception e) {
System.out.println("Catch Exception -> " + e.getMessage());
} finally {
System.out.println("Finally");
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
输出:
Try to do something
Catch Exception -> RuntimeException
Finally
1
2
3
2
3
# return与finally
- 当在
try
块或catch
块中遇到return
语句时,finally
语句块将在方法返回之前被执行。 - 不要在
finally
语句块中使用return
!当try
语句和finally
语句中都有return
语句时,try
语句块中的return
语句会被忽略。这是因为try
语句中的return
返回值会先被暂存在一个本地变量中,当执行到finally
语句中的return
之后,这个本地变量的值就变为了finally
语句中的return
返回值。 - 在特殊情况下
finally
中的代码不会被执行,就比如说finally
之前虚拟机被终止运行的话,finally
中的代码就不会被执行。
// TODO:从字节码理解执行顺序
# 语法糖 try-with-resources
JDK7 之后,Java 新增的 try-with-resource
语法糖来打开资源,并且可以在语句执行完毕后确保每个资源都被自动关闭 。
try (resource declaration) {
// 使用的资源
} catch (ExceptionType e1) {
// 异常块
}
1
2
3
4
5
2
3
4
5
示例:
import java.io.*;
public class RunoobTest {
public static void main(String[] args) {
String line;
try(BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
while ((line = br.readLine()) != null) {
System.out.println("Line =>"+line);
}
} catch (IOException e) {
System.out.println("IOException in try block =>" + e.getMessage());
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 关键字 throws/throw
⭐ throws:用来声明一个方法可能产生的所有异常,不做任何处理而是将异常往上传,谁调用我我就抛给谁。
public class className
{
public void deposit(double amount) throws RemoteException
{
// Method implementation
throw new RemoteException();
}
//Remainder of class definition
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
⭐ throw:用来抛出一个具体的异常类型
public class Test {
public static void main(String[] args) {
User user1 = new User("admin", "123");
User user2 = null;
login(user1);
login(user2);
}
public static void login(User user) {
if (user == null) {
// 这里可以通过继承RuntimeException来自定义异常
throw new RuntimeException("传入用户参数异常");
}
System.out.println("登录成功!");
}
}
class User {
private String username;
private String password;
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
控制台输出
登录成功!
Exception in thread "main" java.lang.RuntimeException: 传入用户参数异常
at test.Test.login(Test.java:25)
at test.Test.main(Test.java:20)
1
2
3
4
2
3
4
catch
块捕获异常,自定义抛出异常。
# 常见问题
⭐ return 同时出现在 try 和 finally 中
public class Test {
public int method() {
int a = 0;
try {
a = 1;
return a;
} finally {
a = 2;
return a;
}
}
public static void main(String[] args) {
Test test = new Test();
System.out.println(test.method()); // 2
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Test {
public int method() {
try {
return 1;
} finally {
return 2;
}
}
public static void main(String[] args) {
Test test = new Test();
System.out.println(test.method()); // 2
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
编辑 (opens new window)
上次更新: 2023/08/20, 21:21:52