目录
异常体系
【分类】
- Error:程序无法处理的系统错误,编译器不做检查
- Exception:程序可以处理的异常,捕获后可能恢复
- RuntimeException:不可预知的,程序应当自行避免(比如加入if(name!=null))
- 非RuntimeException:可预知的,从编译器校验的异常(受检异常)
【从责任角度看】
- Error属于JVM需要负担的责任
- RuntimeException是程序应该负担的责任
- CheckedException可检查异常是java编译器应该负担的责任
【RuntimeException常见的异常】
- NullPointerException – 空指针引用异常
- ClassCastException – 类型强制转换异常
- IllegalArgumentException – 传递非法参数异常
- IndexOutOfBoundsException – 下标越界异常
- NumberFormatException – 数字格式异常
- ArithmeticException – 算术运算异常
- ArrayStoreException – 向数组中存放与声明类型不兼容对象异常
- NegativeArraySizeException – 创建一个大小为负数的数组错误异常
- SecurityException – 安全异常
- UnsupportedOperationException – 不支持的操作异常
【非RuntimeException常见异常】
- ClassNotFoundException 找不到指定class的异常
- IOexception IO操作异常
- FileNotFoundException 找不到指定文件的异常
【Error】
- NoClassDefFoundError 找不到class定义的异常(class或jar不存在、类文件存在但是在不同的域中、大小写问题,javac无视大小写)
- StackOverflowError 深递归导致栈被消耗尽而抛出的异常
- OutOfMemoryError 内存溢出异常
ps:一般我们最需要关注 RuntimeException
受检异常 VS 运行时异常
受检异常意思是说必须try-catch捕捉,否则编译器报错,如 IOException、ClassNotFoundException
运行时异常是程序逻辑错误引起的,比如数组下标越界
先给个例子简单感受下:
/**
* @author wmx
* @date 2019-08-19
*/
public class TestException {
public static void main(String[] args) {
int a = 6;
int b = 0;
try {
if (b == 0) {
throw new ArithmeticException();
//"除数为0"等ArithmeticException,是RuntimException的子类。而运行时异常将由运行时系统自动抛出,不需要使用throw语句,这里把throw new ArithmeticException()去掉也是不影响运行结果的。
}
System.out.println("a/b的值是:" + a / b);
} catch (ArithmeticException e) {
System.out.println("程序出现异常,变量b不能为0。");
//throw new ArithmeticException();
//System.out.println("end");
}
System.out.println("程序正常结束。");
}
}
运行时异常,并且把原始异常捕捉了,并且吞掉了
程序输出:
程序出现异常,变量b不能为0。
程序正常结束。
说明:
捕捉异常,会使try语句块后面的语句执行不到,
但是程序并不会中断
如果代码改成这样呢?
public class TestException {
public static void main(String[] args) {
int a = 6;
int b = 0;
try {
if (b == 0) {
throw new ArithmeticException();
//"除数为0"等ArithmeticException,是RuntimException的子类。而运行时异常将由运行时系统自动抛出,不需要使用throw语句,这里把throw new ArithmeticException()去掉也是不影响运行结果的。
}
System.out.println("a/b的值是:" + a / b);
} catch (ArithmeticException e) {
System.out.println("程序出现异常,变量b不能为0。");
throw new ArithmeticException();
//System.out.println("end");
}
System.out.println("程序正常结束。");
}
}
程序输出:
程序出现异常,变量b不能为0。
Exception in thread “main” java.lang.ArithmeticException
at pers.wmx.exception.TestException.main(TestException.java:20)
把捕捉的异常向外抛,程序中断
但是在方法处不用显示的throws ArithmeticException
再往下看,受检异常方法名必须得throws
public class TestException1 {
public static void main(String[] args) throws IOException {
int a = 6;
int b = 0;
try {
if (b == 0) {
throw new IOException();
}
System.out.println("a/b的值是:" + a / b);
} catch (IOException e) {
System.out.println("程序出现异常,变量b不能为0。");
throw new IOException();
}
System.out.println("程序正常结束。");
}
}
异常使用的正确姿势
不知道你是否和我一样使用异常时常常瞎球用,乱try-catch,
丢到原始异常,用异常控制业务逻辑等等
至少到现在为止我不能保证我完全掌握Java异常的正确使用
- 不要吞掉原异常,可以打log或者再抛出去;
- 不要在for循环中try-catch;
- 不要使用异常来控制业务逻辑;
- 不要直接捕获泛泛的异常 Exception;
- try-catch的代码快不要太大,不好定位,会降低jvm优化效率;
- try-catch产生性能问题,会落快照;
- 不知道怎么处理的异常直接抛出;
(持续更新…)
多个catch块哪个生效
如果多个catch块,异常的父类写在前面,后面的子类就catch不到,直接报错
异常的父类写后面父类异常也catch不到,比如这样
public static void main(String[] args){
int a = 6;
int b = 0;
try {
if (b == 0) {
throw new ArithmeticException();
//"除数为0"等ArithmeticException,是RuntimException的子类。而运行时异常将由运行时系统自动抛出,不需要使用throw语句,这里把throw new ArithmeticException()去掉也是不影响运行结果的。
}
System.out.println("a/b的值是:" + a / b);
}
catch (ArithmeticException e2) {
System.out.println("程序出现异常,变量b不能为0。");
//throw new ArithmeticException();
//System.out.println("end");
}catch (Exception e){
System.out.println("Exception caught");
}
System.out.println("程序正常结束。");
}
是不是有点感觉了?
try-catch-finally 中的return
显然在开发当中我们并不会在catch和finally中return
但是为了更好的理解异常的捕捉我们简单的了解些,而且有面试官也爱问这一块
/**
* @author wmx
* @date 2019-11-19
*/
public class TestException2 {
public static void main(String[] args) {
System.out.println(output());
}
private static int output() {
try{
System.out.println("try-start...");
int a = 1/0;
return 1;
}catch (Exception e){
System.out.println("catch-start...");
return 2;
}finally {
System.out.println("finally-start...");
return 3;
}
}
}
有finally的情况下return3
没有finally的情况下捕捉到异常return2
这个还是没什么难度的
dao调mapper接口异常如何处理
方案一:
捕捉数据库异常,吞掉原有异常,打log
方案二:
捕捉数据库异常,吞掉原有异常,抛出父类异常或自定义异常
方案三:
不管异常,让系统自己向上抛
你觉得哪种方案更好呢?
转载请注明:汪明鑫的个人博客 » 探究 Java异常机制
说点什么
您将是第一位评论人!