1. 受检异常和非受检异常
-
非受检异常:继承RuntimeException的异常都是非受检异常,非受检异常不需要在函数上明确声明throws exception;
-
那么为啥异常要分受检和非受检呢。如果需要明确函数抛出的异常,那么就需要明确一下,并且编译器会自动监测受检异常是否处理,否则会编译报错。非受检异常,这个表示是运行期错误,是不应该发生的,发生了就应该出错才对。
-
那么我们写程序的时候,到底是写受检异常好呢还是非受检异常好。其实不管是定义受检和还是非受检,都要在适当的时候捕获异常,不能因为非受检异常编译器不检查,就不处理异常了,特别是需要资源释放等场景时都要主动去捕获异常。
2. 捕获异常重新生成异常,cause不要忘了
- 先看一下不输出异常cause,那么获取的异常堆栈是什么样的?
首先看一下,如果捕获异常后直接生成新的异常,不带cause,下游输出异常栈的结果是什么?
try {
try {
double r = 1/0;
} catch (Exception e) {
throw new NewException(e.getMessage());
}
} catch(Exception e) {
e.printStackTrace();
}
输出结果异常堆栈信息是,这样的话,只知道异常是由throw new NewException这个地方抛出的,但是什么原因导致这个异常抛出,就不知道了。
org.example.NewException: / by zero
at org.example.AppTest.testException(AppTest.java:99)
- 如果加上异常cause,那么异常堆栈是什么样的?
把上面的抛出异常的语句改一下,改成加上异常原因的方式,throw new NewException(e.getMessage(), e);
try {
try {
double r = 1/0;
} catch (Exception e) {
throw new NewException(e.getMessage(), e);
}
} catch(Exception e) {
e.printStackTrace();
}
输出的异常堆栈如下:
因为加上了异常cause,所以很清楚知道最源头的异常是如何发生的。
org.example.NewException: / by zero
at org.example.AppTest.testException(AppTest.java:99)
Caused by: java.lang.ArithmeticException: / by zero
at org.example.AppTest.testException(AppTest.java:97)```
- 备注,NewExeption的定义如下:
class NewException extends Exception{
public NewException(String msg) {
super(msg);
}
public NewException(String msg, Throwable e) {
super(msg, e);
}
}
3. finnally 对return的影响
- 如果finnally中也有return语句,那么输出结果是什么?
如下所示,那么test的最终返回结果是try中的ret++,还是ret+3?正确答案是:首先计算try中的return语句,ret++,此时ret=1,然后把返回结果1记录下来,这个时候再去执行finally中的return语句,这个时候直接返回ret + 3,即结果是4,那么 直接返回。所以,最终的输出结果是4。
public int test() {
int ret = 0;
try {
return ret++;
} catch (Exception e) {
throw new NewException(e.getMessage(), e);
} finally {
return ret+3;
}
}
- 如果finnally中没有return语句,但是也对try中的return变量,做了操作,会影响try中的return结果吗?
最终test输出结果是1,finally中的ret+2不会影响return结果。为啥呢?因为try中return中的语句执行完成之后,会把计算结果值拷贝下来,然后再去计算finally中的语句,finally不会对return语句的结果造成影响。
public int test() throws NewException {
int ret = 0;
try {
return ret + 1;
} catch (Exception e) {
throw new NewException(e.getMessage(), e);
} finally {
ret = ret + 2;
System.out.println("result:" + ret);
}
}
- 综上所述,不要在finally中return结果,以免影响try中的return结果。其次,finally中对try中return的变量做操作,不会影响
4. try中释放资源
try语句中后面带有一个(),()理解可以创建资源,比如文件、网络端口,等try语句执行完成之后,会自动调用资源的close方法,释放资源。
try(Resource res1 = new Resource();Resource res2 = new Resource())//可指定多个资源,用;隔开{
xx
}
如果不使用该方法,之前的方法,需要在finally中主动释放
try {
Resource res1 = new Resource();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (res1 != null) {
rest1.close();
}
}