一、概述
Java中, 所以的异常都继承自java.lang.Throwable。

Throwable: Throwable是Java中所有错误(error)和异常(Exception)的父类。 错误和异常的区别是异常可以被应用程序处理, 而错误无法被处理。Error: Error是无法处理的错误, 表示程序运行中出现比较严重的问题。大多数Error和代码编写者无关, 表示代码运行时JVM(Java虚拟机)出现的问题。Exception: Exception是程序自身可以处理的异常,Exception有一个重要的子类RuntimeException, 代表运行时异常。这些异常时非检查异常, 应用程序中可以处理,也可以不处理,一般是由程序错误逻辑引起的。除过非检出异常, 其他的异常都是检查异常, 检查异常如果不处理, 程序就无法编译通过。
二、异常(Exception)
1、检查异常(CheckedException)
程序运行中,很容易出现的、情理可容的异常。除了RuntimeException及其子类外, 其他的都是检出异常。检出异常必须被处理, Java编译器会检查这种异常, 当遇到这种异常时,要么使用try/catch捕获它, 要么使用throw抛出它。
常见的检查异常:
| 序号 | 异常名称 | 异常描述 |
|---|---|---|
| 1 | NoSuchFieldException | 表示该类没有指定名称抛出来的异常 |
| 2 | NoSuchMethodException | 表示该类没有指定方法抛出来的异常 |
| 3 | IllegalAccessException | 不允许访问某个类的异常 |
| 4 | ClassNotFoundException | 类没有找到抛出异常 |
| 5 | IOException | IO错误 |
2、非检查异常 (UnCheckedException)
包括运行时异常RuntimeExcption和Error以及其子类,表示编译器不会检查程序是否对其做了处理, 出现运行时异常时,表示程序出现了错误, 需要找出异常并修正它。
| 序号 | 异常名称 | 异常描述 |
|---|---|---|
| 1 | ArrayIndexOutOfBoundsException | 数组越界异常 |
| 2 | NullPointerException | 空指针异常 |
| 3 | IllegalArgumentException | 非法参数异常 |
| 4 | NegativeArraySizeException | 数组长度为负异常 |
| 5 | IllegalStateException | 非法状态异常 |
| 6 | ClassCastException | 类型转换异常 |
三、异常处理
1、异常处理的关键字
-
throw: 在方法内部, 代表抛出这个异常。 -
thorws: 在方法的声明中, 声明程序可能会抛出异常, 由方法的调用者处理。 -
try/catch: 代表捕获异常。 -
finally: 无论是否发生异常, 都会经过finally包含的语句在返回。
2、try-with-resources
Java中很多类库都需要在使用完成或异常发生时关闭资源, 比如Stream、Connection等等, 传统的处理方式:
// 打开资源
Connection conn = //
try{
// 使用资源
}catch(Exception e){
// 处理异常
}finally{
// 判断资源是否被关闭, 如果没有被关闭,则主动关闭资源
if(conn != null){
// 关闭资源也可能抛出异常, 需要注意
conn.close();
}
}
凡是继承自java.io.Closeable 和 java.io.AutoCloseable的子类都可以使用try-with-resources方式进行关闭资源:
try(Connection conn = //){ // 打开资源并且在代码执行结束的时候,无论是否发生异常, 主动关闭资源
// 使用资源
}catch{
// 处理异常
}
3、异常处理流程
Q:如果在try/catch中包含中包含return语句, finally中的代码是否会执行?
W: 一定会执行,finally语句中的代码在return前先执行然后再return。
Q: 如果try/catch和finally中同时包含return语句会返回那一个?
W: 返回finally语句中返回的内容。finally中包含return语句时, 会使try/catch中的return失效, 最终返回finally中返回的内容.
public class UserClient2 {
public static void main(String[] args) {
System.out.println(test());
}
public static String test(){
try{
throw new Exception("-1");
// return "1";
}catch (Exception e){
return "2";
}finally {
return "3";
}
}
}
// Output
// 无论是否抛出异常, 返回的都是3。
Q: finally中包含对try/catch返回内容的更新操作, 返回值时try/catch返回内容, 还是finally更新后的内容。
W: 如果返回的内容时基本类型,则返回的是try/catch返回的值,如果返回的是引用类型, 则返回的是finally语句更新后的值。
int i = 0;
try{
i ++ ;
System.out.println(i);
return i; // 1
}catch(Exception e){
i ++; // 1
System.out.println(i);
}finally{
i++; // 2
System.out.println(i);
}
// Output
// 1
// 2
// 最终返回的是1
可以看到,最终返回的是1, 是因为return时,会先执行return前的代码,然后暂存return的返回值, 再执行finally的代码,最后通过return返回之前保存的内容。所以这里返回的是1,而不是2, 但是对于下面这个例子,则不一样:
List<Integer> valueList = new ArrayList();
try{
valueList.add(1);
System.out.println(valueList);
return valueList;
}catch(Exception e){
valueList.add(2);
System.out.println(valueList);
}finally{
valueList.add(3);
System.out.println(valueList);
}
// Output
// {1,}
// {1,3}
// 最终输出是{1,3}
最终的输出是{1,3}, 主要是因为返回的数据类型, 当返回的是基本类型时,暂存的内容不会改变, 但是返回的是引用类型时,引用类型存的不是变量本身, 而是对变量的引用, 所以当finllay改变了变量的内容时,最终返回结果也会被改变。
总结:
1、 finally的内容一定会被执行。
2、 当try/catch中包含return时, finally的代码也会被执行。return的时候需要注意返回的值类型, 否则返回值会受到影响。
3、 finally中包含return 时, 会直接返回finaly中的值, 导致try/catch中的return失效。