java.lang.ExceptionInInitializerError异常分析

2024-05-13 14:58

本文主要是介绍java.lang.ExceptionInInitializerError异常分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天在项目开发时遇到一个问题,整个项目是使用Spring等框架搭建起来的在运行项目时不报任何的异常信息,就是找不到某个类信息,各方查找该类确实是存在的,最后通过断点跟踪时在异常栈内发现java.lang.ExceptionInInitializerError这个异常信息,但这个异常信息没有在控制台或者日志系统中抛出来,查明原因之后就对症下药最终解决了该问题。查找该问题也着实费了一翻功夫,正好趁此机会把该问题引发的原因及针对这类问题应该如何来避免记录一下。由于该项目中的代码比较复杂,这里举一个简单的例子来说明一下该异常产生的原因。

java.lang.ExceptionInInitializerError

该异常在Java中的继承关系如下:

下面是jdk对该异常的描述

public class ExceptionInInitializerErrorextends LinkageError

静态初始化程序中发生意外异常的信号。抛出 ExceptionInInitializerError 表明在计算静态初始值或静态变量的初始值期间发生异常

从版本 1.4 开始,这个异常已经更新过,符合通用异常链机制。“保存的 throwable 对象”可能是在构造的时候提供的,并且可以通过 getException() 方法来访问,这类对象目前被认为是导致异常的原因,可以通过 Throwable.getCause() 方法以及前面提到的“遗留方法”访问它。

要理解这个异常还得从Java类中的静态变量初始化过程说起,在Java类中静态变量的初始化顺序和静态变量的声明顺序是一致的。为了验证该说法,我们写一个简单的小程序,代码如下:

/*** */
package com.mhy.oo.statics;import java.util.ArrayList;
import java.util.List;/*** @author mhy2011@163.com* @date 2011-11-18*/
public class StaticParams {private static int NUM_A = getA();private static int NUM_B = getB();private static List<String> LIST_A = getListA();private StaticParams() {System.out.println("初始化构造方法");}public static StaticParams getInstance() {return new StaticParams();}private static int getA() {System.out.println("初始化A");return 10;}private static int getB() {System.out.println("初始化B");return 20;}private static List<String> getListA() {System.out.println("初始化List");return new ArrayList<String>();}public static void main(String[] args) {StaticParams.getInstance();}
}

运行该程序,输出结果如下:

调整静态变量NUM_A和NUM_B的声明顺序,其他逻辑不变

然后再次运行该程序,输出结果如下:

说到这,想必聪明的程序员就想到问题原因了。即在某个静态变量的初始化还未执行之前就使用该静态变量。为了模拟该问题产生原因,我们修改上面的代码成一个单例模式,具体代码如下:

/*** */
package com.mhy.oo.statics;import java.util.ArrayList;
import java.util.List;/*** @author mhy2011@163.com* @date 2011-11-18*/
public class StaticParams {private static StaticParams sp = buildStaticParams();private static int NUM_A = getA();private static int NUM_B = getB();private static List<String> LIST_A = getListA();/*** 私有化构造方法*/private StaticParams() {System.out.println("初始化构造方法");}/*** sp的声明在其他几个静态变量之前* * @return*/private static StaticParams buildStaticParams() {if (null == sp) {sp = new StaticParams();}int result = NUM_A * NUM_B; // 基本类型有默认值,此处不会报错,但结果不正确System.out.println("result is :" + result);LIST_A.add("abcd");		//此时LIST_A还未初始化,到此有异常return sp;}/*** 获取StaticParams实例* * @return*/public static StaticParams getInstance() {return sp;}private static int getA() {System.out.println("初始化A");return 10;}private static int getB() {System.out.println("初始化B");return 20;}private static List<String> getListA() {System.out.println("初始化List");return new ArrayList<String>();}public static void main(String[] args) {StaticParams.getInstance();}
}

在上面的例子中,sp变量初始化中使用到的其他的变量,但其他的静态变量还未初始化,故而在sp初始化时就会产生上面的异常,运行上面的程序就可以在控制台看到如下异常信息:

说到这里,想必大家在编程过程中就知道如何来避免该异常信息的产生了吧。


这篇关于java.lang.ExceptionInInitializerError异常分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/986028

相关文章

SpringBoot中HTTP连接池的配置与优化

《SpringBoot中HTTP连接池的配置与优化》这篇文章主要为大家详细介绍了SpringBoot中HTTP连接池的配置与优化的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、HTTP连接池的核心价值二、Spring Boot集成方案方案1:Apache HttpCl

Spring Boot项目打包和运行的操作方法

《SpringBoot项目打包和运行的操作方法》SpringBoot应用内嵌了Web服务器,所以基于SpringBoot开发的web应用也可以独立运行,无须部署到其他Web服务器中,下面以打包dem... 目录一、打包为JAR包并运行1.打包为可执行的 JAR 包2.运行 JAR 包二、打包为WAR包并运行

Java进行日期解析与格式化的实现代码

《Java进行日期解析与格式化的实现代码》使用Java搭配ApacheCommonsLang3和Natty库,可以实现灵活高效的日期解析与格式化,本文将通过相关示例为大家讲讲具体的实践操作,需要的可以... 目录一、背景二、依赖介绍1. Apache Commons Lang32. Natty三、核心实现代

Spring Boot 常用注解整理(最全收藏版)

《SpringBoot常用注解整理(最全收藏版)》本文系统整理了常用的Spring/SpringBoot注解,按照功能分类进行介绍,每个注解都会涵盖其含义、提供来源、应用场景以及代码示例,帮助开发... 目录Spring & Spring Boot 常用注解整理一、Spring Boot 核心注解二、Spr

SpringBoot实现接口数据加解密的三种实战方案

《SpringBoot实现接口数据加解密的三种实战方案》在金融支付、用户隐私信息传输等场景中,接口数据若以明文传输,极易被中间人攻击窃取,SpringBoot提供了多种优雅的加解密实现方案,本文将从原... 目录一、为什么需要接口数据加解密?二、核心加解密算法选择1. 对称加密(AES)2. 非对称加密(R

基于Go语言实现Base62编码的三种方式以及对比分析

《基于Go语言实现Base62编码的三种方式以及对比分析》Base62编码是一种在字符编码中使用62个字符的编码方式,在计算机科学中,,Go语言是一种静态类型、编译型语言,它由Google开发并开源,... 目录一、标准库现状与解决方案1. 标准库对比表2. 解决方案完整实现代码(含边界处理)二、关键实现细

详解如何在SpringBoot控制器中处理用户数据

《详解如何在SpringBoot控制器中处理用户数据》在SpringBoot应用开发中,控制器(Controller)扮演着至关重要的角色,它负责接收用户请求、处理数据并返回响应,本文将深入浅出地讲解... 目录一、获取请求参数1.1 获取查询参数1.2 获取路径参数二、处理表单提交2.1 处理表单数据三、

java变量内存中存储的使用方式

《java变量内存中存储的使用方式》:本文主要介绍java变量内存中存储的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍2、变量的定义3、 变量的类型4、 变量的作用域5、 内存中的存储方式总结1、介绍在 Java 中,变量是用于存储程序中数据

如何合理管控Java语言的异常

《如何合理管控Java语言的异常》:本文主要介绍如何合理管控Java语言的异常问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍2、Thorwable类3、Error4、Exception类4.1、检查异常4.2、运行时异常5、处理方式5.1. 捕获异常

Spring Boot集成SLF4j从基础到高级实践(最新推荐)

《SpringBoot集成SLF4j从基础到高级实践(最新推荐)》SLF4j(SimpleLoggingFacadeforJava)是一个日志门面(Facade),不是具体的日志实现,这篇文章主要介... 目录一、日志框架概述与SLF4j简介1.1 为什么需要日志框架1.2 主流日志框架对比1.3 SLF4