跳至主要内容

增强Java8和11的空指针异常提示

Welcome file

简介

在Java14之前,如果出现NullPointerException,只会知道有对象为null导致空指针,如果在多个对象上调用了方法,那么就很难区分到底哪个对象为null。在 Java14中,JEP 358(详情见参考资料1)的出现改善了这样的情况,丰富了NullPointerException的输出,但目前常用的版本还是Java8或11等长期支持的版本,所以下面介绍一种方法来让8和11也能实现更加丰富的NullPointerException提示。

增加空指针异常提示

示例代码如下:

public static void main(String[] args) {
  	Map<String, String> map = null;
  	demo(map);
}

public static void demo(Map<String,String> map){
  	System.out.println(map.get("foo").toLowerCase());
}

8和11在增强之前的输出如下:

Exception in thread "main" java.lang.NullPointerException
	at com.nereusyi.npe.NpeDemo.demo(NpeDemo.java:18)
	at com.nereusyi.npe.NpeDemo.main(NpeDemo.java:14)

并没有什么有用的信息,根据这段异常也没法判断到底是哪个对象为null。

下面就可以开始动手增强异常提示了,我们可以在https://github.com/odnoklassniki/jvmti-tools/tree/master/richNPE中找到增强异常提示的代码,具体使用方法也在首页中有详细说明。

下载该文件之后,需要手动编译该文件,首页中少了Mac的编译命令,我在这里也补上:

# Linux
g++ -O2 -fPIC -shared -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -olibrichNPE.so richNPE.cpp

# Windows
cl /O2 /LD /I "%JAVA_HOME%/include" -I "%JAVA_HOME%/include/win32" richNPE.cpp

# Mac
g++ -O2 -fPIC -shared -I $JAVA_HOME/include -I $JAVA_HOME/include/darwin -olibrichNPE.so richNPE.cpp

Windows下如果安装了MINGW64,那么也可以使用g++编译(一般装了git for windows都会有)。

编译好之后,会生成一个librichNPE.so(Windows下会生成一个.exe文件)的文件,在运行时候使用如下方式启动就行:

java -agentpath:/path/to/librichNPE.so MainClass

在idea中运行时,需要在Run Configurations中增加VM options,再输入-agentpath:/path/to/librichNPE.so参数就可以。

这时,再运行示例代码时,异常提示就会变成如下所示:

Exception in thread "main" java.lang.NullPointerException: Called method 'get' on null object at bci 6
	at com.nereusyi.npe.NpeDemo.demo(NpeDemo.java:18)
	at com.nereusyi.npe.NpeDemo.main(NpeDemo.java:14)

现在就可以知道是调用了get方法导致的NullPointerException,也就是说map对象是null。

参考资料

[1]JEP 358:https://openjdk.java.net/jeps/358

[2]jvmti-tools:https://github.com/odnoklassniki/jvmti-tools

评论

此博客中的热门博文

国密SM2签名封装成PKCS7格式

在国内做金融行业,难免会有被强制使用国密算法的情况,而且一般还会指定必须使用硬件加密机之类的设备,所以我也稍微的研究了一下国密算法,使用软算法签名并封装 PKCS7 格式(文档中的一个交互)。 以下是基于 Bouncy Castle 的示例,密钥对的生成可以参考 Bouncy Castle 中 test 包下 SM2 相关代码 public static String sign ( ) throws Exception { //加载公钥 byte [ ] plainText = "hello, world" . getBytes ( ) ; FileInputStream input = new FileInputStream ( "F:\\certificate\\public.cer" ) ; CertificateFactory certificateFactory = new CertificateFactory ( ) ; X509Certificate certificate = ( X509Certificate ) certificateFactory . engineGenerateCertificate ( input ) ; input . close ( ) ; //加载私钥,private为换成实际的私钥 PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec ( "private" . getBytes ( ) ) ; //SM2算法实际上为ECC算法,并指定了一些参数值,所以这里的参数是EC KeyFactory factory = KeyFactory . getInstance ( "EC" , "BC" ) ; PrivateKey privateKey = factory . generatePrivate ( spec ) ; //以下为签名并封装成PKCS7格式 byte [ ] signedMessag

Spring Boot Actuator 2 示例

Welcome file 简介 Spring Boot Actuator为应用程序提供了各种开箱即用的运维特性,可以与应用方便的交互和监控。 使用环境:Java 11 和 Spring Boot 2.4.3.RELEASE 集成Spring Boot Actuator 在Spring Boot中集成Spring Boot Actuator与集成其他的框架类似,在 pom.xml 里引入相关的starter就可以: < dependency > < groupId > org.springframework.boot </ groupId > < artifactId > spring-boot-starter-actuator </ artifactId > </ dependency > < dependency > < groupId > org.springframework.boot </ groupId > < artifactId > spring-boot-starter-web </ artifactId > </ dependency > 由于大部分的使用场景还是web,所以这里也用Spring MVC做示例。 配置好 pom.xml 后,默认actuator仅暴露一些基本功能,实际使用中,根据需求暴露对应功能。为了简便测试,这里在 application.yml 中配置暴露全部功能: management : endpoints : web : exposure : include : "*" endpoint : health : enabled : true show-details : always probes : enabled : true shutdown : enabled : true metr

NextCloud数据目录迁移

最近服务器的环境坏了,所以迁移了NextCloud的数据目录。不过在迁移过程中有点小问题。 环境: Ubuntu 18.04 Docker 19.03.7 1.NextCloud页面不正常,Docker日志显示XX目录permission denied 参考了 这里 的做法,不过是把  /var/www/html/   整个目录的权限都修改为  chown -R www-data:www-data ,之后就不再报权限问题了。 2.数据库配置修改 因为NextCloud是在初始化时填的数据库连接信息,所以直接迁移数据目录的情况下,会导致应用连不到新的数据库环境。此时可以找到数据目录下的  config/config.php 文件,直接修改数据库连接配置。