问题描述
反射调用方法时,方法内部抛出了自定义异常,但是无法在反射调用的时候捕获到抛出的自定义异常。
代码如下:
// 自定义异常
public class MyException extends Exception {
private static final long serialVersionUID = -7998753885990231365L;
private String code;
public MyException(String code, String message) {
super(message);
this.code = code;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
// 反射调用的方法
public class MethodThrowMyException {
public String throwMyException() throws MyException {
throw new MyException("1", "自定义异常");
}
}
// 捕获异常
public class Invocation {
public static void main(String[] args) {
try {
Class<?> c = Class.forName("myexception.MethodThrowMyException");
Object o = c.newInstance();
Method m = c.getMethod("throwMyException");
m.invoke(o);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch(MyException e) {
}
}
}
这里会报错,Unreachable catch block for MyException. This exception is never thrown from the try statement body
问题解决
参考文章
可以发现,JDK的API文档中,关于method.invoke的注释说明
InvocationTargetException
是用来处理内部方法抛出异常的
图1
继续看InvocationTargetException
的说明
InvocationTargetException
是一个受检查的异常,包含了由调用方法或构造函数引发的异常
图2
InvocationTargetException
有两个方法可以获取方法内部抛出的异常
图3
因此修改捕获的方法
public class Invocation {
public static void main(String[] args) {
try {
Class<?> c = Class.forName("myexception.MethodThrowMyException");
Object o = c.newInstance();
Method m = c.getMethod("throwMyException");
m.invoke(o);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// 方式一
Throwable targetException = e.getTargetException();
if(targetException instanceof MyException) {
System.out.println("捕获到自定义异常");
System.out.println("code:" + ((MyException) targetException).getCode());
System.out.println("message:" + targetException.getMessage());
}
// 方式二
Throwable cause = e.getCause();
if (cause instanceof MyException) {
System.out.println("捕获到自定义异常");
System.out.println("code:" + ((MyException) cause).getCode());
System.out.println("message:" + cause.getMessage());
}
}
}
}
得到结果:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at myexception.Invocation.main(Invocation.java:12)
Caused by: myexception.MyException: 自定义异常
at myexception.MethodThrowMyException.throwMyException(MethodThrowMyException.java:5)
... 5 more
捕获到自定义异常
code:1
message:自定义异常
可以看到方式一和方式二是一样的,那么getTargetException
和getCause
有什么区别呢
再次看到文档,这里指出getCause()
是首选的方法,因此使用方式二就行了
图4