java_异常
概念:程序运行过程中出现的非正常情况
异常处理的必要性:任何程序都可能存在大量的未知问题、错误;
如果不对这些问题不进行正确处理,则可能导致程序中断,造成不必要的损失。
异常的分类
异常的父类:Throwable,位于java.lang包下
Throwable类中常用的方法:
public String getMessage():返回String类型的异常信息
public void printStackTree():打印跟踪方法调用栈而获得的详细异常信息
产生Error 的原因:硬件问题、软件问题、程序逻辑错误
除运行时(RuntimeException)异常,其他异常均为受查异常(CheckedException),受查异常必须处理
常见运行时异常
1、数组下标越界:
java.lang.ArrayIndexOutOfBoundsException
2、类型转换异常
java.lang.ClassCastException
3、空指针异常
java.lang.NullPointException
4、数据类型转换异常
java.lang.NumberFormatException
异常的产生
1、自动产生异常
运行程序时,遇到错误的代码,自动产生异常,程序自动终止
2、手动产生异常
语法:throw new 异常类名(“实际参数”);
要求:手动抛异常,必须写在方法内
结果:结果相当于return 语句,会导致程序的终止
异常传递:按着方法的调用链方向反方向传递,直至JVM默认处理异常(打印堆栈跟踪信息),最终导致程序终止
消极处理异常
throws :声明异常,定义在方法声明后面(向上报告)(受查异常传递)
修饰符 返回值类型 方法名 (形参列表)throws 异常类名1,异常类名2{}
结果:使用throws只是消极的把异常传递,可以使已检查异常编译通过,推卸责任,并没有解决问题,程序仍然会因异常而终止。
补充
throws对于运行时异常(RuntimeException)无作用
默认所有的方法都声明的有throws RuntimeException();因此运行时异常不声明也可以被捕获到,但是受查异常必须声明才可以被捕获
积极处理异常
语法:
try{
//可能出现异常的语句
}catch(异常类名 e){//捕获异常,并把捕获到的异常传递给e引用
//出现异常后执行的语句
}
积极处理异常的细节
捕获异常时,try后面可以跟多个catch:
结构:try{}catch{}catch{}catch{}catch{}
注意:程序在执行过程中,从第一个catch开始进行所捕获的异常,依次往下,与哪一个catch块中的异常匹配成功,则执行哪一个catch中异常处理的代码
在捕获异常时,可以利用多态,定义catch(父类型异常 e),
可以捕获的异常:本类型+所有的子类型异常
注意:try 后面可以跟多个catch ,但是父类型异常必须放在其子类的后面
补充
try{}finally{} 显示释放监视器锁(线程)
finally和catch 不能同时省略
finally的应用
finally语句:在任何情况下都必须执行的语句
常用结构:
try{
//可能出现的异常语句
}catch(异常类名 e){
//异常处理语句
}finally{
//在任何情况下都必须执行的代码
}
finally的作用:一般用于关闭资源(资源占用内存)
try{}catch{}finally{}中 finally的优先级最大,有返回值时优先执行finally中的返回值
代码示例
public static void main(String[] args) {
int result = method();
System.out.println(result);
}
public static int method(){
int n =10;
try{
throw new RuntimeException(); //1
}catch(Exception e){ //2
n = 20; //3
return n; //4
}finally{ //5
n=30; //6
}
}
/*
上面代码的运行顺序1,2,3,4,5,6,4
当 1 发生异常时,2 捕获异常执行3,4;执行到 4 时,n=20被存储到单独的一块空间中,此时继续向下执行5,6;执行到6时,n=30只是对局部变量n的修改,并没有对之前的独立空间中的n进行修改。最后又执行 4 返回独立空间中n的值20;
return 返回值可以理解为是一块单独的存储空间
(若是finally中有return语句,则try和catch中的return语句无效)
*/
自定义异常
1、自定义异常时,需要根据需求判断异常的等级(运行时异常或是受查异常)。
2、方法声明异常时,尽可能的详细。
方法覆盖
1、方法名,返回值类型,参数列表必粗和父类相同
2、子类的访问修饰符与父类相同或是比父类更宽泛
3、子类中的方法不能抛出比父类更宽泛的异常