java中的异常
异常就是使代码不能够正确运行的因素。java对这些使程序产生错误的因素封装成对象,通过特殊的机制去捕获,然后反馈给使用者。
java中异常类都继承Throwable或继承他的子类,他的直接子类有三个。
error 指系统错误,比如堆栈溢出等,无特殊情况下一般不需要考虑。下面是error的一些子类。
Exception是需要我们重点关注的对象,这个异常是可以被抛出的基本类型。它有一个特殊的子类RuntimeException,比如数组下标越界,算数异常、空指针等,这类异常不需要我们主动抛出和去进行捕获,所以也叫不受检异常。
Exception下除了RuntimeException都叫受检异常,比如文件未找到异常等一些io异常。调用抛出这些异常的方法必须try catch或者向上抛出。
StackRecorder这类异常很少见,虽然继承了Throwable,但是没有任何自己的方法和属性。里面的注释写着“创建用于在日志记录中记录调用者堆栈跟踪。“,这个一般也不考虑。
异常抛出throw、throws
throw、throws一般都是配套使用的。
前面有提到,如果你在方法中抛出一个非运行时异常(针对Excetion下),你必需再次捕获它,或者向上抛出。事实上,这里你可以直接将捕获的e抛出,因为1.8开始,在编译时,就知道你捕获的是否属于运行时异常,即使你捕获的是Exception。不过如果你在try里面使用io流等,编译时还是会让你再次捕获或者向上抛出。
如果调用了一个抛出受检异常的方法时,会强制让你去捕获,或者再次向上抛出。如果方法抛出的是RuntimeException,就没有这种要求,并且还是能被调用者捕获该方法内的异常。
当你抛出一个Error,也是不需要去捕获,或者向上抛出的。一般我们不去抛error。
public class TestException {
public static int show() throws Exception {
try{
System.out.println(1/0);
}catch (Exception e){
throw new RuntimeException();
}
return 10;
}
public static void main(String[] args) {
try{
System.out.println(TestException.show());
}
catch (ArithmeticException a){
System.out.println(a);
}
catch (RuntimeException r){
System.out.println(r);
}catch (Exception e){
System.out.println(e);
}
}
}
调用者捕获的异常,实际是throw 出去的异常,不是throws处的异常,和代码1/0发生的异常。这里的输出是java.lang.RuntimeException。throws只决定,调用者在编译期是否要强制捕获或者抛出。
catch 处捕获的异常要从小到大。
throws处的异常必须是throw或者他的父类。
throw和return
throw和return看似是没有什么关系的,但是我们在使用时特别要注意一些情况,就是在final中使用return会使catch中throw的异常不能抛出,外界捕获不到。这样就会造成一些问题,比如在Spring中的事务方法中,如果出现上面的那种情况,就会导致事务不会回滚,因为spring的事务方法只有抛出异常,才会回滚。如果你又想返回一些信息,就可以自定义一个异常,将需要的信息存入,这样就不一定要在final块返回内容了,同时调用者也可以获得对应的信息。
这和catch和final中都有return很相似,如果有final块,catch中return的内容先暂存,如果final中有return,返回final中return的信息,没有就继续返回catch中return的内容。