java.lang.ExceptionInInitializerError原因及解决办法

java.lang.Object
java.lang.Throwable
java.lang.Error
java.lang.LinkageError
java.lang.ExceptionInInitializerError

ExceptionInInitializerError 通常意味着在静态初始化块或静态变量初始化过程中发生了异常。

静态代码块异常:如果在静态代码块中有任何异常抛出,都会导致此错误。

public class StaticBlock {

    private static int state;

    static {
        state = 42 / 0; //除0异常
    }
}

静态变量初始化异常:如果静态变量在初始化时抛出了异常,也会导致此错误。(编译后实际上也是在静态代码块里面)

public class Example {
    private static final int number = Integer.parseInt("abc"); // 这里会抛出NumberFormatException
}

解决方法

一般来说,查看堆栈跟踪都能找出问题所在。

  1. 检查静态初始化块:确保静态初始化块中没有抛出异常的代码。
  2. 检查静态变量初始化:确保所有静态变量的初始化都是安全的,没有抛出异常。

工作中的例子

java.lang.ExceptionInInitializerError at com.xxx.xx.Service.onInit(Service.java:654) 

查看654行代码,引用了一个静态类。

static {
    try {
        String path = "/data/data/com.xxx.xx/lib/libxxplay.so";
        File file = new File(path);
        if (file.exists()) {
            SFLogger.d(TAG, "use /data/data/com.xxx.xx/lib/libxxplay.so");
            System.load(path);
        } else {
            SFLogger.d(TAG, "use /system/lib/libxxplay.so");
            System.loadLibrary("xxplay");
        }
    } catch (Exception e) {
        SFLogger.e(TAG, "JniUtil loadLibrary exception = " + e.getMessage());
    }
}

以上代码咋一看好像也没什么问题啊,异常都catch住了。

但如果仔细研究就会发现,这里的问题是滥用了Exception,没有针对具体异常进行捕获。查看loadLibrary源码发现其可能会抛出SecurityExceptionUnsatisfiedLinkError或者NullPointerExceptionSecurityExceptionNullPointerException的父类都是RuntimeException,是一种异常(Exception),UnsatisfiedLinkError的父类是LinkageError,是一种错误(Error),所以如果这里发生了UnsatisfiedLinkError,通过Exception是捕获不了的,必须通过他们的共同父类Throwable来进行捕获。当然,最好还是针对具体的异常进行捕获,不要用这种扩大化的捕获方式,容易隐藏问题。

    /**
     * Loads the native library specified by the <code>libname</code>
     * argument.  The <code>libname</code> argument must not contain any platform
     * specific prefix, file extension or path. If a native library
     * called <code>libname</code> is statically linked with the VM, then the
     * JNI_OnLoad_<code>libname</code> function exported by the library is invoked.
     * See the JNI Specification for more details.
     *
     * Otherwise, the libname argument is loaded from a system library
     * location and mapped to a native library image in an implementation-
     * dependent manner.
     * <p>
     * The call <code>System.loadLibrary(name)</code> is effectively
     * equivalent to the call
     * <blockquote><pre>
     * Runtime.getRuntime().loadLibrary(name)
     * </pre></blockquote>
     *
     * @param      libname   the name of the library.
     * @exception  SecurityException  if a security manager exists and its
     *             <code>checkLink</code> method doesn't allow
     *             loading of the specified dynamic library
     * @exception  UnsatisfiedLinkError if either the libname argument
     *             contains a file path, the native library is not statically
     *             linked with the VM,  or the library cannot be mapped to a
     *             native library image by the host system.
     * @exception  NullPointerException if <code>libname</code> is
     *             <code>null</code>
     * @see        java.lang.Runtime#loadLibrary(java.lang.String)
     * @see        java.lang.SecurityManager#checkLink(java.lang.String)
     */
    @CallerSensitive
    public static void loadLibrary(String libname) {
        Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);
    }

参考

ExceptionInInitializerError | Android Developers

When Does Java Throw the ExceptionInInitializerError? | Baeldung

Chapter 11. Exceptions

`java.lang.ExceptionInInitializerError` 表示在类的静态初始化块、静态变量初始化或类的构造函数中发生了异常。而 `java.lang.RuntimeException: java.lang.ExceptionInInitializerError` 是将 `ExceptionInInitializerError` 封装在 `RuntimeException` 中抛出。以下是一些常见的解决办法: #### 检查静态代码块中的资源加载 在静态代码块中加载资源文件时,可能会因为文件不存在或加载路径错误导致 `NullPointerException`。例如在引用 [1] 和 [2] 中,使用 `getClassLoader().getResourceAsStream` 加载配置文件时,若文件路径错误或文件不存在,会返回 `null`,后续操作就会抛出 `NullPointerException`。 ```java // 错误示例,可能加载为 null InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"); Properties properties = new Properties(); properties.load(is); // 若 is 为 null,会抛出 NullPointerException // 正确做法,添加空值检查 InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"); if (is != null) { Properties properties = new Properties(); try { properties.load(is); } catch (IOException e) { e.printStackTrace(); } } else { System.err.println("未能找到 druid.properties 文件"); } ``` #### 检查依赖冲突 项目中的依赖冲突可能会导致类加载异常,从而引发 `ExceptionInInitializerError`。可以使用 Maven 或 Gradle 的依赖分析工具来检查和解决依赖冲突。例如在 Maven 中使用 `mvn dependency:tree` 命令查看依赖树,找出冲突的依赖并排除它们。 ```xml <dependency> <groupId>冲突依赖的groupId</groupId> <artifactId>冲突依赖的artifactId</artifactId> <exclusions> <exclusion> <groupId>需要排除的依赖的groupId</groupId> <artifactId>需要排除的依赖的artifactId</artifactId> </exclusion> </exclusions> </dependency> ``` #### 检查 JDK 版本 确保项目使用的 JDK 版本与代码兼容。不兼容的 JDK 版本可能会导致类加载异常或其他编译问题。可以在 IDE 中检查项目的 JDK 配置,以及 `JAVA_HOME` 环境变量是否正确设置。 #### 检查静态变量初始化逻辑 静态变量初始化时可能会调用其他方法或依赖其他类,若这些方法或类出现异常,会导致 `ExceptionInInitializerError`。检查静态变量初始化的代码逻辑,添加异常处理或日志输出,以便定位问题。 ```java public class DruidUtils { static DataSource dataSource = null; static { InputStream is = DruidUtils.class.getClassLoader().getResourceAsStream("servletDemo.properties"); Properties prop = new Properties(); try { if (is != null) { prop.load(is); } else { System.err.println("未能找到 servletDemo.properties 文件"); } } catch (IOException e) { e.printStackTrace(); } try { if (!prop.isEmpty()) { dataSource = DruidDataSourceFactory.createDataSource(prop); } } catch (Exception e) { e.printStackTrace(); } } // 其他方法... } ``` #### 清理项目缓存 有时 IDE 或构建工具的缓存可能会导致编译问题。可以尝试清理 IDE 的缓存,例如在 IntelliJ IDEA 中选择 `File` -> `Invalidate Caches / Restart`。同时,也可以清理 Maven 或 Gradle 的本地仓库缓存,删除 `~/.m2/repository` 或 `~/.gradle/caches` 目录下的相关缓存文件,然后重新构建项目。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值