我的2019年3月博客文章“ Java会出现更好的默认NullPointerException消息吗? ”是在尚未针对特定JDK版本针对更好的NullPointerException消息的JEP 草案编写时编写的。 此后,该JEP草案成为JEP 14的 目标 JEP 358(“ Helpful NullPointerExceptions”) 。 更好的是,初始实现( JDK-8218628 ) 已经在JDK 14分支中 ,并且可以在JDK 14 Early Access Build Build 20(2019/10/23)中使用 。
在本文中,我将针对JDK 14 Early Access Build 20运行先前文章中介绍的示例代码 ,以演示现在提供的其他详细信息。 要查看为故意引入导致NullPointerException
的各种情况而编写的示例代码,请参阅前面的文章或查看GitHub上的源代码 。
下载JDK 14 Early Access Build 20并按其路径指向该文件后,运行java -version
时会看到以下内容:
openjdk version "14-ea" 2020 - 03 - 17 OpenJDK Runtime Environment (build 14 -ea+ 20 - 879 ) OpenJDK 64 -Bit Server VM (build 14 -ea+ 20 - 879 , mixed mode, sharing)
在正确配置了JDK 14 Early Access Build 20之后 ,我重新构建了前面提到的源代码 ,然后使用Java启动器重新运行了该代码,而没有任何新选项。 该输出(如下所示)与以前的JDK版本的输出没有实质性差异。
========================================= | # | # 1 : Element [ null boolean array | ] on : Element [ 0 ] on ========================================= java.lang.NullPointerException at dustin.examples.npe.NpeDemo.demonstrateFirstExampleIndexAccessOnNullBooleanArray(Unknown Source) at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ================================= | # | # 2 : .length on null boolean [] | ================================= java.lang.NullPointerException at dustin.examples.npe.NpeDemo.demonstrateSecondExampleLengthOnNullBooleanArray(Unknown Source) at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ======================================= | # | # 3 : Assigning float : Assigning to null float [] | ======================================= java.lang.NullPointerException at dustin.examples.npe.NpeDemo.demonstrateThirdExampleAssigningValueToElementOfNullFloatArray(Unknown Source) at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ====================================== | # | # 4 : Accessing field on null object | : Accessing field on object | ====================================== java.lang.NullPointerException at dustin.examples.npe.NpeDemo.demonstrateFourthExampleAccessInstanceFieldOfNullObject(Unknown Source) at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) =================== | # | # 5 : throw null ; | ; | =================== java.lang.NullPointerException at dustin.examples.npe.NpeDemo.demonstrateFifthExampleThrowingConstantNull(Unknown Source) at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ================================================ | # | # 6 : Method invocation on null instance field | : Method invocation on ================================================ java.lang.NullPointerException at dustin.examples.npe.NpeDemo.demonstrateSixthExampleMethodInvocationOnNullInstanceField(Unknown Source) at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ============================================= | # | # 7 : () on null instance field | () on synchronized () on instance field | ============================================= java.lang.NullPointerException at dustin.examples.npe.NpeDemo.demonstrateSeventhExampleSynchronizedNullInstanceField(Unknown Source) at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ========================================================================== | >>> Null Lost in Long Series of Method Invocations in Single Statement | ========================================================================== java.lang.NullPointerException at dustin.examples.npe.NpeDemo.demonstrateNullLostInSeriesOfMethodInvocationsInSingleStatement(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ======================================================= | >>> Null Lost in Dereferenced Constructor Arguments | ======================================================= java.lang.NullPointerException at dustin.examples.npe.NpeDemo.demonstrateNullLostInConstructorAcceptingMultiplePotentiallyNullArgumentsDereferenced(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ================================================== | >>> Null Lost in Dereferenced Method Arguments | ================================================== java.lang.NullPointerException at dustin.examples.npe.NpeDemo.demonstrateNullLostInMethodAcceptingMultiplePotentiallyNullArgumentsDereferenced(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source)
如以上输出所示,即使使用新的JDK 14 Early Access Build 20,当我正常运行应用程序时,也看不到有关NullPointerException
的任何新的详细信息。 我包含了此输出,以表明需要一个特殊的标志来启用更详细的NullPointerException
,并使其更方便地比较带有和不带有其他详细信息的输出。 下一个输出清单显示了将Java启动器传递给标志-XX:+ShowCodeDetailsInExceptionMessages
时提供的其他详细信息:
========================================= | # | # 1 : Element [ null boolean array | ] on : Element [ 0 ] on ========================================= java.lang.NullPointerException: Cannot load from byte / boolean array because java.lang.NullPointerException: Cannot load from array because "<local1>" is null at dustin.examples.npe.NpeDemo.demonstrateFirstExampleIndexAccessOnNullBooleanArray(Unknown Source) at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ================================= | # | # 2 : .length on null boolean [] | ================================= java.lang.NullPointerException: Cannot read the array length because "<local1>" is null at dustin.examples.npe.NpeDemo.demonstrateSecondExampleLengthOnNullBooleanArray(Unknown Source) at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ======================================= | # | # 3 : Assigning float : Assigning to null float [] | ======================================= java.lang.NullPointerException: Cannot store to array because "<local1>" is null array because java.lang.NullPointerException: Cannot store to float array because at dustin.examples.npe.NpeDemo.demonstrateThirdExampleAssigningValueToElementOfNullFloatArray(Unknown Source) at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ====================================== | # | # 4 : Accessing field on null object | : Accessing field on object | ====================================== java.lang.NullPointerException: Cannot read field "nullInstanceField" because "<local1>" is null at dustin.examples.npe.NpeDemo.demonstrateFourthExampleAccessInstanceFieldOfNullObject(Unknown Source) at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) =================== | # | # 5 : throw null ; | ; | =================== java.lang.NullPointerException: Cannot throw exception because "null" is null at dustin.examples.npe.NpeDemo.demonstrateFifthExampleThrowingConstantNull(Unknown Source) at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ================================================ | # | # 6 : Method invocation on null instance field | : Method invocation on ================================================ java.lang.NullPointerException: Cannot invoke "String.isEmpty()" because "this.nullInstanceField" is null at dustin.examples.npe.NpeDemo.demonstrateSixthExampleMethodInvocationOnNullInstanceField(Unknown Source) at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ============================================= | # | # 7 : () on null instance field | () on synchronized () on instance field | ============================================= java.lang.NullPointerException: Cannot enter synchronized block because "this.nullInstanceField" is null at dustin.examples.npe.NpeDemo.demonstrateSeventhExampleSynchronizedNullInstanceField(Unknown Source) at dustin.examples.npe.NpeDemo.demonstrateJdk8218628Examples(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ========================================================================== | >>> Null Lost in Long Series of Method Invocations in Single Statement | ========================================================================== java.lang.NullPointerException: Cannot invoke "dustin.examples.npe.DysfunctionalLocation$Province.getCity()" because the return value of "dustin.examples.npe.DysfunctionalLocation$Nation.getProvince()" is null at dustin.examples.npe.NpeDemo.demonstrateNullLostInSeriesOfMethodInvocationsInSingleStatement(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ======================================================= | >>> Null Lost in Dereferenced Constructor Arguments | ======================================================= java.lang.NullPointerException: Cannot invoke "java.lang.Long.longValue()" because "<local6>" is null at dustin.examples.npe.NpeDemo.demonstrateNullLostInConstructorAcceptingMultiplePotentiallyNullArgumentsDereferenced(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source) ================================================== | >>> Null Lost in Dereferenced Method Arguments | ================================================== java.lang.NullPointerException: Cannot invoke "java.lang.Long.longValue()" because "<local6>" is null at dustin.examples.npe.NpeDemo.demonstrateNullLostInMethodAcceptingMultiplePotentiallyNullArgumentsDereferenced(Unknown Source) at dustin.examples.npe.NpeDemo.main(Unknown Source)
JEP 358解释了使用此标志来查看其他NullPointerException
详细信息:“可以使用新的boolean
命令行选项-XX { + | - } ShowCodeDetailsInExceptionMessages
-XX { + | - } ShowCodeDetailsInExceptionMessages
。 该选项将首先具有默认值' false
',以便不打印消息。 它旨在在以后的版本中默认情况下在异常消息中启用代码详细信息。” 如我们所见,此功能默认情况下最初处于关闭状态,但是有计划在将来启用更详细的NullPointerException
消息。
最近的一条Tweet问了一个问题:“如果字节码不包含变量名,它将如何工作?” 这个问题通过提供一个具体的例子来继续:“假设我们有像Object a = ....; a.getName(); //NPE
这样的代码Object a = ....; a.getName(); //NPE
Object a = ....; a.getName(); //NPE
Object a = ....; a.getName(); //NPE
NPE会Object a = ....; a.getName(); //NPE
哪种消息?” 尽管在前面显示的一系列测试中都包含了一个示例,但我认为我将在此提供一个针对性更强的示例来回答该问题。 下一个代码清单(也在GitHub上提供 )显示了改编自Tweet中使用的示例的代码。
package dustin.examples.npe; /** * Simple demonstration to answer Tweet-ed question * "How it will work if bytecode doesn't contain variable names?" * ( https://twitter.com/2doublewhiskey/status/1180365953240055809 ). */ public class TwoDoubleWhiskeyTweetExample { public static void main( final String[] arguments) { final Person person = null ; person.getName(); //NPE } public static class Person { private String name; public Person( final String newName) { name = newName; } public String getName() { return name; } } }
下一个屏幕快照显示了使用JDK 14 Early Access Build 20(不带java
启动器标志-XX:+ShowCodeDetailsInExceptionMessages
运行此简单应用程序的结果。
如屏幕快照所示,在JDK 14 Early Access Build 20中使用-XX:+ShowCodeDetailsInExceptionMessages
标志可提供与此简单NullPointerException
示例相关的其他详细信息:“无法调用” dustin.examples.npe.TwoDoubleWhiskeyTweetExample $ Person.getName() ”,因为“ <local1> ”为空”
GitHub上提供了一个更简单甚至更接近Tweet-ed问题中提供的原始示例的示例。
JEP 358 (“ 有用的NullPointerExceptions ”)可能不像新JDK发行版中的其他一些JEP那样浮华,但最终可能是每天为Java开发人员提供比其一些浮华同行更高的价值 。 有许多示例将对您有所帮助,JEP本身以及本文引用的我的代码示例中都阐明了许多示例情况。
翻译自: https://www.javacodegeeks.com/2019/10/better-npe-messages-in-jdk-14.html