静态方法抛出运行时异常导致反射生成实例失败
文章目录
场景还原
1. 启动时,static属性获取时便打印了异常,不过没有注意到。 2. 之后在异常无法捕获之处既无正常往下走到return,也没有被Catch捕获异常,甚至在该行无法Step in进入debug,最终被外层的finally块处理。
生成实例失败的类
public class InnerPositionThread extends MonitorThread { Logger logger = LoggerFactory.getLogger(getClass()); private static Map<String, List<BlockField>> blockAttrCfg = BlockUtils.getBlocks("innerposition.xml"); }
抛出运行时异常的方法
public class BlockUtils { public static Map<String, List<BlockField>> getBlocks(String templateName) { try { // do something } } catch (Exception var14) { var14.printStackTrace(); throw new RuntimeException(var14); } }
无法捕获异常之处
try { Object monitor; // 下面这行将会异常 monitor = (IfMonitor)Class.forName(mClass).newInstance(); return null; } catch (Exception var4) { log.error("启动监视器失败 " + config.getName() + " (" + monitorKey + ")", var4); return getStartFalseResponse(config, monitorKey, isCreate ? "监视器已建立,激活失败" : "启动监视器失败"); }
重试
另起工程简化示例进行查看原因。
接口
public interface InterfaceA { void functionA(); }
类
静态属性初始化抛出异常
public class ClassImplA implements InterfaceA { private static Logger logger = LoggerFactory.getLogger(ClassImplA.class); private static Long staticProperties = initStaticProperties(); private static Long initStaticProperties() { throw new RuntimeException("ClassImplA throw runtime exception"); } @Override public void functionA() { logger.info("function A be called!"); } }
测试main方法
public static void main(String[] args) { logger.info("start main"); Object classAImpl; String className = ClassImplA.class.getName(); logger.info("start get class A"); try { classAImpl = (InterfaceA)Class.forName(className).newInstance(); ((InterfaceA)classAImpl).functionA(); } catch (Exception e) { logger.error("catch exception反射失败" + e.getMessage()); } catch (Error e) { logger.error("catch error反射失败" + e.getMessage()); } finally { logger.info("in finally end get class A"); } logger.info("end main"); }
测试输出
六月 02, 2020 2:34:52 下午 forname.MainTest main 信息: start main 六月 02, 2020 2:34:52 下午 forname.MainTest main 信息: start get class A 六月 02, 2020 2:34:52 下午 forname.MainTest main 严重: catch error反射失败null 六月 02, 2020 2:34:52 下午 forname.MainTest main 信息: in finally end get class A 六月 02, 2020 2:34:52 下午 forname.MainTest main 信息: end main
观察捕获到Error,而非Exception,打印堆栈可见,其最终抛出的错误是ExceptionInInitializerError。
java.lang.ExceptionInInitializerError at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:264) at forname.MainTest.main(MainTest.java:16) Caused by: java.lang.RuntimeException: ClassImplA throw runtime exception at forname.ClassImplA.initStaticProperties(ClassImplA.java:12) at forname.ClassImplA.<clinit>(ClassImplA.java:9) ... 3 more
通过查看该类的继承发现ExceptionInInitializerError继承LinkageError,再继承Error,最终继承Throwable,所以该ExceptionInInitializerError不会被Exception的catch块捕获。
结论
通过请教他人得知:
- 这类Error必须干掉,不能带进程序,
- static属性初始化也不允许抛出异常,
- catch块也不能去抓取error或者Throwable的错误。