关于java异常的整理

一、异常分类

java异常层级结构

  • Throwable:所有异常的根接口
    • Error:严重错误,程序无法处理和恢复
      • 例如VirtualMachineError,OOMError等
    • Exception:异常,程序可以捕获并可能恢复
      • RuntimeException: 运行时异常,无需强制捕获
        • NullPointerException
        • ClassCastException
        • ArithmeticException
        • IllegalArgumentException
      • IOException: IO操作异常
        • FileNotFoundException
        • SocketException
      • SQLException: SQL数据库访问异常
      • TimeoutException: 超时异常
      • ParseException: 解析错误异常
      • OtherException: 其他领域特定的异常
        • HttpException
        • ASFException
      • 自定义Exception:用户自定义的业务异常

从另一个角度看java异常分为Checked Exception和Unchecked Exception

  • Checked Exception: 需要捕获或者声明抛出的异常,如果没有处理则不能编译通过。主要包括Exception及其子类,不包括RuntimeException。例如IOException、SQLException等。
  • Unchecked Exception: 不需要强制捕获的异常,可以不处理。主要包括RuntimeException及其子类。例如NullPointerException、ClassCastException等

Checked Exception举例:

public class Test{
    
    
    public static void main(String[] args) throws IllegalAccessException {
    
    
        int a = new Random().nextInt(10);
        System.out.println(a);
        if(a % 2 == 1){
    
    
            throw new IllegalAccessException("This is an checked exception.");
        }
    }
}

这里如果不声明(throws)或捕获(try-catch)异常编译会报错

在这里插入图片描述
加上throws IllegalAccessException编译通过,运行结果如下
在这里插入图片描述

Unchecked Exception举例:

public class Test {
    
    
    public static void main(String[] args){
    
    
        int a = new Random().nextInt(10);
        System.out.println(a);
        if(a % 2 == 1){
    
    
            throw new IllegalArgumentException("This is an unchecked exception.");
        }
    }
}

这里没有throws或try-catch编译通过
在这里插入图片描述
运行结果如下
在这里插入图片描述
ps::注意上面例子上两种异常(IllegalAccessException和IllegalArgumentException),不要看错了

二、throw、throws、try-catch-finally

  • throw: 用于抛出一个异常对象,通常在方法体内使用。

例如:

throw new IOException("文件读取错误");
  • throws: 声明一个方法可能抛出的异常类型,出现在方法签名中。

例如:

public void readFile(String file) throws IOException {
    
    
  // 方法实现
}
  • try-catch-finally: 用于捕获异常,try代码块表示需要捕获异常的代码,catch表示捕获到异常后的处理逻辑,finally表示需要额外处理的逻辑
    finally中的内容是一定会执行的,无论有没有捕获异常。常用于关闭IO流等做一些收尾操作。

例如:

try {
    
    
  readFile(file); 
} catch (IOException e) {
    
    
  // 处理IO异常
} finally {
    
    
  // 额外逻辑
}

三、CglibAopProxy中对异常的处理

在CglibAopProxy中有一个内部类CglibMethodInvocation,而CglibMethodInvocation中的proceed()方法对捕获的异常做了一个逻辑处理

        @Nullable
        public Object proceed() throws Throwable {
    
    
            try {
    
    
                return super.proceed();
            } catch (RuntimeException var2) {
    
    
            	// RuntimeException或其子类直接抛出 ---- 1
                throw var2;
            } catch (Exception var3) {
    
    
            	// 非RunTimeException需根据Cglib代理的方法抛出的异常判断 ---- 2
            	// 是代理方法抛出的异常或该异常的子类则 ---- 3
            	// 若不是则抛出UndeclaredThrowableException异常 ---- 4
                if (!ReflectionUtils.declaresException(this.getMethod(), var3.getClass()) && !KotlinDetector.isKotlinType(this.getMethod().getDeclaringClass())) {
    
    
                    throw new UndeclaredThrowableException(var3);
                } else {
    
    
                    throw var3;
                }
            }
        }

上述代码2、3、4实现主要由if语句条件中ReflectionUtils.declaresException()方法实现
方法参数:
Method method:代理的方法
Class<?> exceptionType:抛出的异常(不是代理方法抛出的),这里是aop中抛出的IllegalAccessException

    public static boolean declaresException(Method method, Class<?> exceptionType) {
    
    
        Assert.notNull(method, "Method must not be null");
        // 获取代理方法中抛出的异常类型
        Class<?>[] declaredExceptions = method.getExceptionTypes();
        Class[] var3 = declaredExceptions;
        int var4 = declaredExceptions.length;
		
		// 判断捕获的异常是否是代理方法抛出的异常或该异常子类
        for(int var5 = 0; var5 < var4; ++var5) {
    
    
            Class<?> declaredException = var3[var5];
            if (declaredException.isAssignableFrom(exceptionType)) {
    
    
                return true;
            }
        }

        return false;
    }

举例说明:
这里自定义注解+aop切面增强某个controller方法时抛出了IllegalAccessException异常
在这里插入图片描述
controller中并未throws任何异常
在这里插入图片描述
运行结果
在这里插入图片描述
返回给前端的结果也是这个,并没有返回我们写的IllegalAccessException
打断点调试
先走到CglibAopProxy这
因为IllegalAccessException不是RuntimeException的子类,所以走到了if条件语句这
在这里插入图片描述
进入到ReflectionUtils.declaresException()方法
在这里插入图片描述
查看控制台debug的内容可知他从method中获取的异常类型
在这里插入图片描述
可见是没有获取到任何异常的,因为上面controller中并未手动抛出任何异常
所以最后ReflectionUtils.declaresException(this.getMethod(), var3.getClass())返回的结果是false
抛出UndeclaredThrowableException异常
看名字能知道这个异常的意思是未声明的异常

4、关于UndeclaredThrowableException

一文搞懂 UndeclaredThrowableException

猜你喜欢

转载自blog.csdn.net/weixin_43636205/article/details/132121382