Thursday, January 30, 2020

Recent Valhalla News (Late January 2020)

There has been significant discussion, design, implementation, and testing related to aspects of OpenJDK Project Valhalla in recent months, but a couple things have struck me as particularly interesting over the last few days in terms of Valhalla progress. I briefly summarize those here.

 

Latest on JDK Release Associated with Valhalla

Frédéric Parain has posted "Valhalla EG 20200129" on the valhalla-spec-experts mailing list. This posting constitutes the meeting notes from the Valhalla Expert Group Meeting on 29 January 2020.

There are several interesting discussion points in these Valhalla Expert Group Meeting notes, but none may be more interesting than the answer to the question, "Is there a JDK release targeted for Valhalla?" In response to that question, the notes provide "bullets" that constitute Brian Goetz's response:

  • "too early to say"
  • "VM work is consolidating"
  • "language work still needs significant work before having a road-map"
  • "first release won't have all the features but have to have further additions in mind"

Although there's still much work required for Valhalla, I interpret these comments in a positive manner, especially when compared to responses to a similar question in months and years past.

 

The Future of Integer

The previously referenced Valhalla Expert Group Meeting Notes for 29 January 2020 include this note attributed to Brian Goetz: "Retrofitting of Integer: seemed impossible, but now seems more feasible."

I am not certain of the context of those notes, but reading these notes did make me think of Brian Goetz's discussion in the December 2019 edition of "State of Valhalla" regarding "Integer and friends." In particular, Goetz discusses migrating primitives by changing the "wrapper types (such as Integer and friends) to be interfaces" so that "these interfaces will become the reference projection for the primitives." Or, as Rafael Winterhalter articulates it, "inline class int implements Integer."

Related to this, Goetz wrote in the 6 December 2019 post "Long-awaited State of the Values docs" (I added emphasis):

The other major AHA buried in this document is the realization that the language and VM models need not align 100%. LWorld is the right VM model, but we can use it as a _translation target_ rather than our language model. This allows the primitives to blossom into full inline classes. In the new world, we have inline classes and identity classes, primitives are mostly just inline classes, and the relationship between inlines and identity classes is isomorphic to the current relationship between primitives and classes.

Goetz also discusses "migrating Integer and friends to be inline-friendly" in the post "Superclasses for inline classes."

 

Optional and Integer Will Be Interfaces Instead of Classes

The December 2019 "State of Valhalla" document explains that the Optional class of today will be changed to an interface and that the "wrapper types Integer and friends" will be migrated "to be interfaces, using the same techniques as with migrating Optional."

One downside to this conversion of Optional, Integer, and friends from classes to interfaces is that comparisons of getClass() calls in existing code against these literal types will break (because the classes implementing the interfaces will be returned in the future instead of the interface name). To deal with this, Bug JDK-8237074 ("[lworld] Compiler should emit a warning if code compares the result of getClass() against the class literal for an interface") has been written and addressed in the repo-valhalla repository. Any legacy code that compares the results of a getClass() call to a literal such as java.lang.Integer.class or java.util.Object.class may not work correctly with these changes, but at least there will be a warning.

 

New Edition of "State of Valhalla" Coming Soon?

It sounds possible that there will soon be an updated version of "State of Valhalla." In the 29 January 2020 Vallhalla EG Meeting notes, there are these notes attributed to Brian Goetz:

  • "working on reference projection as an interface or an abstract class"
  • "possible update next week, working on simplification"
  • "would lead to rewrite of 'State of Valhalla'"

 

Interfaces IdentityObject and InlineObject Introduced

In the December 2019 edition of "State of Valhalla," Goetz introduced "new top interfaces" IdentityObject and InlineObject:

To distinguish between inline and identity classes at compile time and runtime, we introduce a pair of restricted interfaces: IdentityObject and InlineObject. Inline classes implicitly implement InlineObject; identity classes implicitly implement IdentityObject.

JDK-8237069 ("[lworld] Introduce and wire-in the new top interfaces") captures the need to write these interfaces and Srikanth Adayapalam has added these new interfaces to repo-valhalla. Adayapalam describes these changes in the post "[LWorld] Definition and wiring in of the new top interface types.," which includes a link to the changeset. This changeset includes the new interfaces IdentityObject and InlineObject. From this new source, we can see that both interfaces are in the java.lang package and both interfaces have no methods defined ("marker" or "tagging" interfaces similar to java.io.Serializable).

The Javadoc for IdentityObject simply states, "A restricted interface implemented by all identity objects." Similarly, the Javadoc for InlineObject simply states, "A restricted interface implemented by all inline objects."

 

Conclusion

Project Valhalla continues to progress and developments in recent months create a feeling that Valhalla design and implementation is solidifying.

Friday, December 20, 2019

General, Safe, and Deterministic Foreign Memory Access in JDK 14

In the post "JDK 14 Rampdown: Build 27," I summarized the numerous JDK 14-targeted features newly available with JDK 14 Early Access Build #27. There is already another JDK 14 Early Access Build available and this one [Build 28 (2019/12/18)] includes one particularly interesting feature: Enhancement JDK-8234049 ["Implementation of Memory Access API (Incubator)"]. This is the implementation of JEP 370 ["Foreign-Memory Access API (Incubator)"], which is summarized as, "Introduce an API to allow Java programs to safely and efficiently access foreign memory outside of the Java heap."

JEP 370 is intended to achieve a "foreign memory API" that provides "generality", "safety", and "determinism" (with each of these means described in further detail in the JEP). The JEP also states that this foreign memory API is intended as an alternative to currently used approaches (java.nio.ByteBuffer and sun.misc.Unsafe). Downsides and limitations of both of these currently available alternates are discussed in the JEP.

The JEP points out that libraries "access foreign memory" to "avoid the cost and unpredictability associated with garbage collection," to "share memory across multiple processes," and to "serialize and deserialize memory content by mapping files into memory." It adds that "the Java API does not provide a satisfactory solution for accessing foreign memory."

JEP 370's "Description" section introduces the implementation of the foreign memory access API. The section begins, "The foreign-memory access API introduces three main abstractions: MemorySegment, MemoryAddress and MemoryLayout." The section then describes these three main abstractions: "A MemorySegment is used to model a contiguous memory region with given spatial and temporal bounds. A MemoryAddress can be thought of as an offset within a segment. Finally, a MemoryLayout is a programmatic description of a memory segment's contents."

After several detailed examples of using the foreign memory access, the JEP's "Description" section states, "The foreign-memory access API will initially be provided as an incubating module, named jdk.incubator.foreign, in a package of the same name."

Additional background details related to JEP 370 are available in OpenJDK mailing list messages. One key thread starts with the message "RFR JDK-8234049: Implementation of Memory Access API (Incubator)." The CSR for this JEP [JDK-8234050: Implementation of Memory Access API (Incubator)] presents alternate useful descriptions. Javadoc-based documentation for the foreign memory access API is also temporarily available at http://cr.openjdk.java.net/~mcimadamore/panama/memaccess_javadoc/jdk/incubator/foreign/package-summary.html.

The JEP 370 implementation is included in the JDK 14 Early Access Build #28 and available to try.

Saturday, December 14, 2019

JDK 14 Rampdown: Build 27

Mark Reinhold's recent post "JDK 14 is now in Rampdown Phase One" announced that "we are now in Rampdown Phase One" and that "the overall feature set is frozen." JDK 14 Early Access Build #27 (2019/12/12) is a hefty build. In this post, I summarize some of the changes associated with JDK 14 Early Access Build 27 that are particularly interesting to me.

One might say that JDK 14 Early Access Build 27 is the "records build." This build is full of updates related to the implementation of the records preview feature (JEP 359). Here are some of the changes associated with this "records build" filled with JEP 359 implementation changes (note that there are already bugs written and fixed for records):

  • JEP 359 JDK-8222777: Records (Preview)
  • Sub-Task JDK-8227113: Specification for java.lang.Record
  • Sub-Task JDK-8225053: Preview APIs support for records
  • Sub-Task JDK-8233526: JVM support for records
  • Sub-Task JDK-8225054: Compiler implementation for records
  • Sub-Task JDK-8225057: Java Language Specification changes for Records
  • Sub-Task JDK-8225058: JVM Specification changes for Records
  • Sub-Task JDK-8225055: Javadoc for records
  • Sub-Task JDK-8225052: javax.lang.model support for records
  • Sub-Task JDK-8226314: com.sun.source support for records
  • Enhancement JDK-8235359: Simplify method Class.getRecordComponents()
  • Bug JDK-8235550: Clarify record reflective support specification
  • Bug JDK-8235369: Class.toGenericString need to be updated for records
  • Bug JDK-8235446: confusing error message for records with no parens
  • Bug JDK-8234101: Compilation error thrown when repeating annotation is used on record component
  • Bug JDK-8235474: JShell does not handle records properly

Although JEP 359/Records (Preview) will likely dominate interest of many Java developers in the JDK 14 Early Access Build 27, there are other interesting changes in this build that are summarized here (with links to more details and quotes from the change descriptions):

In addition to the changes that I called out above, other changes associated with JDK 14 Early Access Build 27 include changes to areas that have changes in many JDK 14 builds (Shenandoah garbage collector, Z garbage collector [ZGC], Java Flight Recorder, and the Java packaging tool).

The JDK 14 Early Access Build 27 Release Notes state that "SSLv2Hello and SSLv3 have been removed from the default enabled TLS protocols." The release notes add that "If a client or server still needs to use the SSLv3 protocol they can do so by enabling it via the jdk.tls.client.protocols or jdk.tls.server.protocols system properties or with the SSLSocket.setEnabledProtocols(), SSLServerSocket.setEnabledProtocols() and SSLEngine.setEnabledProtocols() APIs."

I am excited about Records in Java 14 and look forward to playing with them via the OpenJDK 14 Early Access Build 27.

Monday, November 18, 2019

JDK 14: Records, Text Blocks, and More

Today's Mark Reinhold post "JEPs proposed to target JDK 14: 305, 343, 359, 366, & 368" proposes targeting five more JEPs to JDK 14. Some highly anticipated features are among this group, although all but one are proposed to be in "preview" or "incubating":

  • JEP 305: Pattern Matching for instanceof (Preview)
  • JEP 343: Packaging Tool (Incubator)
  • JEP 359: Records (Preview)
  • JEP 366: Deprecate the ParallelScavenge + SerialOld GC Combination
  • JEP 368: Text Blocks (Second Preview)

The Java SE 13 Java Language Updates document describes preview features (JEP 12): "A preview feature is a new feature whose design, specification, and implementation are complete, but which is not permanent, which means that the feature may exist in a different form or not at all in future JDK releases."

JEP 11 ("Incubator Modules") describes "incubator modules" as "a means of putting non-final APIs and non-final tools in the hands of developers, while the APIs/tools progress towards either finalization or removal in a future release."

Four of the five JEPs proposed today for targeting JDK 14 are "preview" or "incubator" and so will be subject to potentially "not exist .... at all in future JDK releases" or potential "removal in a future release." However, the opportunity to take these features for a spin is welcome and there seems likely that these features will eventually become permanent even if they have some modifications. We could have these JEPs officially targeted for JDK 14 by Thanksgiving!

Additional Resources

JDK 14: CMS GC is OBE

JDK 14 Early Access Build #23 (2019/11/13) is now available. One of the more noteworthy changes with this build is the removal of the Concurrent Mark Sweep garbage collector. JEP 291 ["Deprecate the Concurrent Mark Sweep (CMS) Garbage Collector"] deprecated the Concurrent Mark Sweep (CMS) garbage collector back in 2017 with JDK 9 and JEP 363 ["Remove the Concurrent Mark Sweep (CMS) Garbage Collector"] has been targeted for JDK 14 to remove the CMS garbage collector altogether.

The next screen snapshot demonstrates that the CMS garbage collector was still available with JDK 14 Early Access Build #22.

With that JDK 14 Early Access Build #22, we see that specifying -XX:+UseConcMarkSweepGC is allowed with only a deprecation warning shown: "Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release."

The next screen snapshot demonstrates that CMS cannot be specified as a garbage collector as of JDK 14 Early Access Build #23:

When trying to run the Java application with -XX:+UseConcMarkSweepGC, the error message now shown states, "Ignoring option UseConcMarkSweepGC; support was removed in 14.0".

Although the removal of the CMS garbage collector was the biggest change I noticed in JDK 14 Early Access Build #23, there were a few other changes that I found to be somewhat interesting. These include:

Saturday, November 2, 2019

Six More JEPs Proposed for JDK 14

A recent Mark Reinhold message announces six new "JEPs proposed to target JDK 14": JEP 345, JEP 361, JEP 363, JEP 364, JEP 365, and JEP 367. Assuming no objections are made by November 7, these JEPs will be targeted to JDK 14 along with previously targeted JEPs JEP 349 ("JFR Event Streaming"), JEP 352 ("Non-Volatile Mapped Byte Buffers"), and JEP 358 ("Helpful NullPointerExceptions"). This post summarizes each of these six JEPs proposed for targeting JDK 14.

JEP 345: NUMA-Aware Memory Allocation for G1

The succinct "Summary" of JEP 345 states, "Improve G1 performance on large machines by implementing NUMA-aware memory allocation." Two important "non-goals" of this JEP indicate that the JEP is only intended to add NUMA (non-uniform memory access) support to the G1 garbage collector and only for Linux. However, the JEP also points out that "the parallel collector, enabled by by -XX:+UseParallelGC, has been NUMA-aware for many years."

JEP 361: Switch Expressions (Standard)

JEP 361 moves switch expressions from their JEP 325 "preview" status to "standard" status. Along the way, JEP 354 (targeted at JDK 13) made this change to the preview switch expressions feature: "To yield a value from a switch expression, the break with value statement is dropped in favor of a yield statement." The "History" section of JEP 361 discusses switch expressions support in preview status in JDK 12 and JDK 13 and explains why it is proposed for standard status with JDK 14: "Feedback on JDK 13 suggests that this feature is now ready to be made final and permanent in JDK 14."

JEP 363: Remove the Concurrent Mark Sweep (CMS) Garbage Collector

JEP 363's concise "Summary" states, "Remove the Concurrent Mark Sweep (CMS) garbage collector." The Concurrent Mark Sweep (CMS) garbage collector was deprecated with JEP 291 (JDK 9) and this JEP aims to remove it altogether with JDK 14.

JEP 364: ZGC on macOS / JEP 365: ZGC on Windows

The goals of JEP 364 and JEP 365 are to "port the ZGC garbage collector" to macOS and Windows operating systems respectively.

JEP 364's "Motivation" section states, "While we expect users that require the scalability of ZGC to use Linux-based environments, it is not uncommon that developers use Macs for local development and testing, before deploying applications." Although JEP 365 lacks an explicit "Motivation" section, its motivation is probably similar to that for JEP 364.

JEP 365's "Non-Goals" section states, "It is not a goal to support Windows 10 and Windows Server older than version 1803, since older versions lack the required API for placeholder memory reservations."

JEP 367: Remove the Pack200 Tools and API

The "Summary" section of JEP 367 begins with this statement, "Remove the pack200 and unpack200 tools, and the Pack200 API in the java.util.jar package." This removal of these tools and APIs was advertised in Java SE 11 via JEP 336 when they were deprecated.

The "Motivation" sections of both the deprecation JEP 336 and the removal JEP 367 list three reasons for deprecating and removing Pack200 and conclude with this statement, "Overall, the cost of maintaining Pack200 is significant, and outweighs the benefit of including it in Java SE and the JDK."

The "Risks and Assumptions" section of JEP 336 includes this statement, "We assume that developers who use pack200 to shrink application JARs can switch to either the jlink tool or the jpackage tool to create application-specific runtimes with an optimized form factor." There is discussion regarding the suitability of jlink and jpackage on the r/java sub-reddit.

Java SE Specification Impacts

Iris Clark has posted that two of these JEPs have Java SE scope. She writes that JEP 361 (switch expressions standard) and JEP 367 (removing Pack200) are "of scope 'SE' [and] have been Proposed to Target for Java SE 14."

Conclusion

If all six of these JEPs proposed for JDK 14 get targeted for JDK 14, there will be nine JEPs associated with JDK 14. Two that I'm particularly looking forward to are the standardizing the switch expressions feature with JEP 361 and better NPE messages with JEP 358.

Saturday, October 26, 2019

Better NPE Messages in JDK 14

My March 2019 blog post "Better Default NullPointerException Messages Coming to Java?" was written when the draft JEP for better NullPointerException messages had not yet been targeted to a particular JDK release. Since then, that draft JEP became JEP 358 ("Helpful NullPointerExceptions"), which has been targeted for JDK 14. Even better, the initial implementation (JDK-8218628) is already in the JDK 14 branch and is available to play with in JDK 14 Early Access Builds Build 20 (2019/10/23).

In this post, I will run the example code introduced in my previous post against the JDK 14 Early Access Build 20 to demonstrate the additional details now provided. To see that example code that was written to intentionally introduce a variety of situations resulting in NullPointerExceptions, see that earlier post or view the source code on GitHub.

With the JDK 14 Early Access Build 20 downloaded and pointed to by my path, I see the following when I run 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)

With the JDK 14 Early Access Build 20 configured appropriately, I rebuilt the source code mentioned previously and then re-ran the code with the java launcher without any new options. The output from this (shown below) is not materially different from the output with previous JDK versions.

=========================================
| #1: Element [0] on null boolean array |
=========================================

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 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 |
======================================

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 |
================================================

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: synchronized() on null 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)

As the above output demonstrates, even with the new JDK 14 Early Access Build 20, I don't see any new detailed information regarding NullPointerExceptions when I run my application as normal. I included this output to show that a special flag is needed to enable the more detailed NullPointerExceptions and to make it more convenient to compare the output without and with the extra details. The next output listing shows the additional details provided when the java launcher is passed the flag -XX:+ShowCodeDetailsInExceptionMessages:

=========================================
| #1: Element [0] on null boolean array |
=========================================

java.lang.NullPointerException: Cannot load from byte/boolean 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 to null float[] |
=======================================

java.lang.NullPointerException: Cannot store to float array because "<local1>" is null
 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 |
======================================

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 |
================================================

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: synchronized() on null 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 explains the use of this flag for seeing additional NullPointerException details: "The feature can be toggled with the new boolean command-line option -XX:{+|-}ShowCodeDetailsInExceptionMessages. The option will first have default 'false' so that the message is not printed. It is intended to enable code details in exception messages by default in a later release." As we see, this feature is initially turned off by default, but there is a plan to enable the more detailed NullPointerException messages in the future.

A recent Tweet asked the question, "How it will work if bytecode doesn’t contain variable names?" The question continued by providing a specific example: "Suppose we have code like Object a = ....; a.getName(); //NPE What kinds of message NPE would have?" Although an example of this is included in my battery of tests shown earlier, I thought I'd provide a more focused example here in response to that question. The next code listing (which is also available on GitHub) shows code adapted from the example used in the 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;
      }
   }
}

The next screen snapshot shows the result of running this simple application with the JDK 14 Early Access Build 20 without and then with the java launcher flag -XX:+ShowCodeDetailsInExceptionMessages.

As the screen snapshot indicates, using the -XX:+ShowCodeDetailsInExceptionMessages flag with the JDK 14 Early Access Build 20 provides this additional detail related to this simple NullPointerException example: "Cannot invoke "dustin.examples.npe.TwoDoubleWhiskeyTweetExample$Person.getName()" because "<local1>" is null"

An example that is simpler and even closer to the original example provided in the Tweet-ed question is available on GitHub.

JEP 358 ("Helpful NullPointerExceptions") may not be as flashy as some other JEPs that come to new JDK releases, but it may be one that in the end provides more value to Java developers on a daily basis than some of its flashier peers. There are numerous examples where this will be helpful and many of those example situations are spelled out in the JEP itself and in my code examples referenced in this post.