一、概述
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
失效。
网友评论