使用Java的反射调用方法应注意的异常处理

先看下面的代码,看看程序执行会是什么样的结果:
 1import java.lang.reflect.Method;
 2/**
 3 * @author Unmi
 4 */
 5public class ExceptionTest {
 6
 7   public static void main(String[] args) {
 8      try{
 9         foo1();
10      }catch (MyException me) {
11         System.out.println("Exception Type: MyException");
12      }catch (Exception e) {
13         System.out.println("Exception Type: Exception");
14      }
15   }
16
17   public static void foo1() throws Exception{
18      Method method = ExceptionTest.class.getDeclaredMethod("foo2",new Class[]{});
19
20      //注意调用foo2时,foo2方法会抛出MyException异常
21      method.invoke(null,new Object[]{});
22   }
23
24   public static void foo2() throws Exception{
25      throw new MyException(); //foo2方法直接抛出异常
26   }
27}
28
29//一个自定义的异常
30class MyException extends Exception{
31
32}

简单分析上面的代码,代码中自定义了一个异常类,main调用了方法foo1,而方法foo1调用了方法foo2,在方法foo2中抛出的异常是MyException,该异常向上传播,在main方法中被catch,那么是不会会第一个catch语句捕获到,在控制台下打印出"Exception Type: MyException"呢?其实不然,异常会被第二个catch语句捕获,实际执行结果是"Exception Type: Exception"。

也就是尽管foo2方法中抛出的是MyException,但是让foo1通过反射方式调用后,异常被重新封装。从foo1方法中执向外面的异常实际是"InvocationTargetException",也就是执行method.invoke方法的异常了,那么在foo1中如何知道触发的实际异常呢,InvocationTargetException有一个方法getTargetException()可以获取到是MyException异常。

如果我们想在main方法中更细致的处理实际方法执行所抛出的异常,应如何做呢?我们可以改写foo1中的反射调用代码行
1method.invoke(null,new Object[]{});

替换如下,让在foo2中触发的实际异常向外抛
1try{
2    method.invoke(null,new Object[]{});
3}catch (InvocationTargetException ite) {
4    //确定实际引发异常MyException,Exception子类,所以强型转换
5    throw (Exception)ite.getTargetException();
6}

这样的话,这个异常将在main方法的第一个catch块被捕获,异常类型被还原成MyException。

我是在项目中使用Struts,写了一个BaseAction,在BaseAction中根据参数反向调用相应的Action Perform方法时,在BaseAction中也是写成上面代码那样的异常捕获方式,结果发现只要是Action Perform方法中抛出的异常总是作为Exception被捕获的,而不能正确处理异常中描述的业务含业。

用Struts做项目时,经常会写自己的BaseAction,由这个BaseAction去分发执行哪一个实际方法,并且由它统一根据上抛的异常处理错误信息时就应该注意到这种问题。 永久链接 https://yanbin.blog/java-reflect-exception-handle/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。