ExceptionInInitializerError-静态代码块的细节

ExceptionInInitializerError-静态代码块的细节

背景描述

某日调试的过程中发现一个非常奇怪的错误,在IDEA中debug过程中我没有办法获取一个已经申请好的静态变量,接口也每每执行到此处就会跳错。那么按思路来说,缩小问题范围,集中精力去发现这个问题根源。于是编写单元测试对这一小截代码进行测试。出处部分主要来自下面这一段

    public static Map urlMapping = new ConcurrentHashMap<>();

    static {
        ConfigUtil.init();
        urlMapping.put("xxx", PARTICIPLESURL);
        urlMapping.put("yyy", INTENTURL);
        urlMapping.put("zzz", SORTURL);
    }

甚至报错了NoClassDefFoundError的错误。一般来说,NoClassDefFound这个错误常发生于依赖冲突的场景,但现在在调用自己的类出现这个问题就非常不可思议。日志中的错误栈也比较冗长,影响了一开始捕获关键信息的难度。

问题现象

观察日志栈中可以发现有一个区分度比较明显的错误

java.lang.ExceptionInInitializerError

这个就是答案的解。这个错误的意思其实是在静态代码块中如果加载出错的会统一跳出这个Error。因为是Error还没办法被普通的try-catch捕获。
那之前的那个说的那个错误

noclassdeffounderror: could not initialize class

又是怎么回事呢?我们知道jvm在需要加载类时会先加载类中的静态代码块和静态变量等。静态代码块出现了没有被捕获的错误,代码块崩溃,导致整个类加载失败,jvm找不到这个类,顺理成章的引出了上面这个错误。这个错误很容易往依赖冲突的方向去想,而偏离了问题的本质。
那么代码的问题又处在哪里呢?主要是ConcurrentHashMap的k和v是不允许为null空值的,而在当时环境下被赋予了空值报错没有接住导致的这个问题。ConcurrentHashMap不允许kv空值和本身需要做线程同步有关,而HashMap就没有这个问题,在非多线程环境下,即一块内存只会被一个线程访问时,还是使用HashMap就可以了。效率上也比ConcurrentHashMap快,因为ConcurrentHashMap内部还有为线程同步上锁的问题存在。

解决方式

没什么特别值得书写的,最重要的还是知道了这个报错的原因,解决方式无非根据场景处理了空值现象。

你可能感兴趣的:(ExceptionInInitializerError-静态代码块的细节)