工作日🐇🐇🐇
这两天在刷Java技能树,刚好刷到异常,也让我自己认识到很多的不足,这里来总结一下,感谢c站技能树,这里有很多知识可以学习😗⭐⭐⭐
以下结合本人经验+c站技能树知识做了一个汇总😼😼
文章目录
异常基础知识
Exception分为两类,一类是:运行时异常(RuntimeException)另一类是编译时异常(书上写的可称非运行时异常或已检查异常,是因为在Exception类中的子类只有RuntimeException是运行时异常。)
在进行异常捕获的时候,一定要记住要先捕获小异常,再捕获大异常
RuntimeException:不可查异常
对于不可查异常,编译器不会强制要求处理的异常,而编译时异常(非运行时异常),编译器会强制要求进行处理。
就是你在写代码的时候(编译期间)他就会给你报错,这就是可查异常,编译器会警告你,否则就是不可查异常(下面的例子非常清楚了)
常见的运行时异常(虽然编译也能通过,但是还是需要我们处理避免出现这些异常。)
- ArrayIndexoutofBoundsException 访问数组时使用无效索引值
- NullPointException 尝试访问null对象成员,空指针异常
- ClassCastException 类型转换异常
- ArithmeticException 非法的算术运算,如以0作除数
- NumberFormatException 数字转化格式异常
- IllegalArgumentException 方法接收到非法参数
- IndexOutOfBoundsException 下标超出范围异常
Checked:可查异常
除了上述的Runtime异常和其子类异常之外,其他的异常就是Checked异常
例子
ublic static void t1(){
try {
System.out.println("hi");
}catch (IndexOutOfBoundsException e){
e.printStackTrace();
}
}
public static void t2(){
try {
System.out.println("hi");
}catch (NullPointerException e){
e.printStackTrace();
}
}
可以看到编译器没有报错,现在来试试可查异常
public static void t3(){
try {
System.out.println("hi");
}catch (IOException e){
e.printStackTrace();
}
}
编译器提示说:在try里面压根就不会抛出什么异常,因为只有一个输出语句,因此试图捕获这个异常是错误的
总结
对上述简单实验得到总结:如果一个catch语句试图捕获一个类型为XXXException的异常,那么它对应的try语句必须有可能抛出XXXException或其子类异常
自动关闭的try语句(补充)
之前出国一篇文章讲述关闭资源的正确方式:传送门
这样关闭的方式是没问题,但是代码比较臃肿,代码可读性不高。Java7之后,Java新增了自动关闭资源的try语句,也就是try后面加一对圆括号,括号里可以声明、初始化一个或者多个资源,这个资源就是你最后要关闭的资源,比如文件流啊、数据库连接之类的
🐕🦺🐕🦺注意,这里可以帮忙关闭的前提,是括号里的资源是可关闭的,也就是实现了AutoCloseable接口或者Closeable接口,实现这两个接口就必须实现close方法,不然你在括号里写的东西都不能关闭,那就没什么意义了
try(var oos = new ObjectOutputStream()){
...
}catch(){
...
}
放在圆括号里声明、初始化,这样try语句就会自动关闭它们
🤓🤓几乎全部的资源类都实现了上面的两个接口,所以不用太担心
try-catch-finally
一般例子为:
try {
//可能出现异常的代码
}catch(异常类型1 变量名1) {
//处理异常的方式1
}catch(异常类型2 变量名2) {
//处理异常的方式2
}
....
finally {
//一定会执行的代码
}
📣📣📣注意:一个try语句可以对应多个catch,并且遵循先捕获小异常,后捕获大异常
finally块陷阱
大家都知道,finally块总是会被执行,但是还是有一些小陷阱
finally执行规则(终止情况)
有一种情况他不会执行
也就是:System.exit(0);
try(){
...
System.exit(0);
}finally{
...do something...
}
重要
程序运行到System.exit(0);之后,finally块不会再被执行
这个语句的作用:停止当前线程和所有其他当场死亡的线程
而finally块并不能让已经停止的线程继续执行
当System.exit(0)被调用时,虚拟机退出前要执行两项清理工作:
- 执行系统中注册的所有关闭钩子(这个是安全的)
- 如果程序调用了System.runFinalizerOnExit(true);那么JVM会对所有还未结束的对象调用Finalizer(这种方式非常危险,而且现在已经过时了)
finally块和方法返回值
经典案例一
public static void main(String[] args) {
int a = test();
System.out.println(a); // 7
}
public static int test(){
int count = 5;
try {
return count++;
}finally {
System.out.println("finally块被执行");
return ++count;
}
}
最终输出的结果是7,这表明,finally块也被执行了
所以他根本就没有执行try语句里面的return语句
⭐⭐当Java程序执行try语句catch语句遇到了return语句,那么return语句会导致该方法立即结束,系统执行完return语句之后,并不会立即结束该方法,而是去寻找有没有finally语句块,如果没有,那么该方法终止,并且返回相应的值;如果有,那么系统就立即开始执行finally块——只有当finally块执行完成之后,系统才会跳回来根据return语句结束方法;如果finally语句块中使用了return语句导致方法结束,则finally块已经结束了方法,系统将不会跳回去执行try语句、catch语句里的任何代码
经典案例二
public static void main(String[] args) {
int test2 = test2();
System.out.println(test2); //5
}
public static int test2(){
int count = 5;
try {
int a = 20 / 0;
}finally {
System.out.println("finally被执行");
return count;
}
}
上述代码在try语句块必然会抛出异常RuntimeException异常,但是程序没有使用catch去捕获,那么在这种情况下,这个异常应该导致test2方法非正常中止,test2应该没有返回结果
但是实际情况确实,并没有抛出异常,而是输出了结果5,就像int a = 20 / 0;这句话没啥用的感觉
🍊🍊🍊总结:一定要理解finally块执行流程,当程序执行try、catch语句块时候,遇到throw语句时,throw语句会导致这个方法结束,这个是没问题的;但是系统并不会马上结束,他会先去寻找该异常 处理流程中是否包含finally语句,如果没有,则马上抛出异常,中止方法;如果有,那么立即执行finally语句块——只有当finally语句块执行完成后,系统才会跳回来抛出异常、中止程序。
当然,如果finally里包含return语句,那么程序就不会回去