异常处理-定义
当jvm运行时,发现某一行的代码运行出现无法处理的情况,会new一个异常对象继承exception,抛给调用的方法栈。
- 如果有catch方法捕获到该对象,会交给其处理,否则会将该异常抛出,异常显示在控制台,中断运行
异常处理-格式
try{
//有可能发生异常的代码块
}catch(异常类型1 对象1){
//针对此类异常的处理操作
}catch(异常类型2 对象2){
//针对此类异常的处理操作
}catch(异常类型3||异常类型4 对象2){
//针对此类异常的处理操作
//接收时候可以用逻辑运算符
}…
finally{
//异常的统一出口,一定会运行到,无论是否产生异常
//比如,try中获取了某个文件,无论是否发生异常,我们在运行最后都要把这个文件释放出来
}
异常处理-异常体系
- Error : 错误!coder无法用代码处理,只能避免,比如内存溢出
- Exception: 异常!程序处理时的逻辑问题,一般用try…catch处理
- 捕获更粗的异常catch,不能在更细的异常之前
- RuntimeException: 非受检异常,运行时候有一定概率会出现异常(比如读取用户输入的数据计算除法,有可能分母为0)
finally
除非代码运行过程中,电脑直接关机等外部因素,否则finally一定运行,如下图finally也要运行(面试常问)
finally的运行顺序
上文会返回28,是因为,在return之前,会先运行finally,再return。在jvm运行到return p代码时候,会存储下来p所在的内存地址,但并不向上返回,此时finally语句会在此地址中的age进行修改,因此在返回后,打印的age是28。
但上述情况,仅仅针对引用数据类型,如果是数值类型,则运行结果会不同,见下,因此return之前针对数值类型,会复制一份,因此,finally中对于i的修改不会有任何影响,下列代码返回值依旧为12
归纳如下:
try_catch_finally执行流程:
1、先计算try中的返回值,并将返回值存储起来(引用类型存储的是地址,数值类型是复制值),等待;
2、执行finally代码块
3、将之前存储的返回值,返回出去。
注意:
finally代码中不建议带有return,因为程序会在上述流程中提前中断,因为返回的是finally中的return,而非try或者catch中的return。
另外,如果在try或者catch中停止了jvm,如停电,或者通过System.exit(0)退出jvm
public class Mytest {
public static void main(String[] args) {
System.out.println(haha());//返回12
}
public static int haha(){
int i=10;
try{
i=12;
return i;
}catch (Exception e){
return -1;
}finally {
i=-20;
}
}
}
但如果系统直接退出的话,finally是不会执行的,下面的System.exit(status:0)会导致jvm退出,因此finally不会执行
- try_catch_finally中,catch与finally可以省略一个,但是不能同时省略。虽然格式上允许省略catch,但是程序实践中一般不这样操作,因为异常此时我们就不处理了。。。
throws
异常是否抛出(throws),还是内部捕获(try_catch_exception),应该如何选择?
如果是写的工具类,因为外面的参数导致问题,比如参数格式不对,参数不是我们想要的等等,则需要将这个异常抛出,throws。
throw
如果我们需要主动抛出某个异常,则使用throw,例子如下:
public void setAge(int age) {
if(age<0||age>100){
RuntimeException e=new RuntimeException("年龄不合理");
throw e;
}else{
this.age=age;
}
}
或者如下:
自定义异常
//通过继承RuntimeException或者Exception,重写一参构造方法,来自定义异常
public class AgeRuntimeException extends RuntimeException{
public AgeRuntimeException(String message) {
super(message);
//可以在这个地方,针对该类型的异常,进行专门处理,比如通过短信或者邮件提醒coder
}
}