tag:blogger.com,1999:blog-65174502045083395142024-02-29T22:39:31.350-07:00Inspired by Actual Events<p><strong>Dustin's Software Development Cogitations and Speculations</strong></p>
<p>My observations and thoughts concerning software development (general development, Java, JavaFX, Groovy, Flex, ...).</p>
<p>Select posts from this blog are syndicated on <a href="https://dzone.com/">DZone</a> and <a href="https://www.javacodegeeks.com/">Java Code Geeks</a> and were formerly syndicated on <a href="https://www.javaworld.com/">JavaWorld</a>.</p>@DustinMarxhttp://www.blogger.com/profile/10790950138196529391noreply@blogger.comBlogger136418tag:blogger.com,1999:blog-6517450204508339514.post-18842367803751647522023-03-27T07:35:00.076-06:002023-03-27T07:35:00.135-06:00OpenJDK 21 Compiler Warning on Constructor Calling Overridable Methods<p>THe <a href="https://jdk.java.net/21/"><b>OpenJDK 21 beta 15</b> early access build</a> (released <b>23 March 2023</b>) adds an <a href="http://marxsoftware.blogspot.com/2010/10/javacs-xlint-options.html" target="_blank">-Xlint warning</a> to the Java compiler to notify Java developers when a class's <a href="http://marxsoftware.blogspot.com/2012/10/netbeans-overridable-method-call-ctor.html" target="_blank">constructor calls an overridable method</a>. Specifically, changes for <a href="https://bugs.openjdk.org/browse/JDK-8015831" target="_blank">JDK-8015831</a> ("Add lint check for calling overridable methods from a constructor") and <a href="https://bugs.openjdk.org/browse/JDK-6557145" target="_blank">JDK-6557145</a> ("Warn about calling abstract methods in constructors") are avalable in <b>OpenJDK 21 beta 15</b>. <a href="https://bugs.openjdk.org/browse/JDK-8299995" target="_blank">CSR JDK-8299995</a> ("Add lint check for calling overridable methods from a constructor") provides background details and justificatiion for these new warnings.</p>
<p>Two example classes are needed to demonstrate the new warnings with a parent class whose constructor calls overridable methods implemented by the extending class.</p>
<p><b><code>ParentWithAbstractMethod</code>: Parent Class with <code>abstract</code> Method Called by Constructor</b></p>
<pre name="code" class="java">
package dustin.examples.constructorcalls;
public abstract class ParentWithAbstractMethod
{
/**
* Constructor to be called by extending classes.
*/
protected ParentWithAbstractMethod()
{
initializeCustomLogic();
}
/**
* Initialize instance's custom logic.
*
* Because this {@code abstract} method is called by the constructor,
* it will trigger the "this-escape" {@code -Xlint} warning.
*/
protected abstract void initializeCustomLogic();
}
</pre>
<p><b><code>ConstructorCallsDemonstration</code>: The Child/Extending Class</b></p>
<pre name="code" class="java">
package dustin.examples.constructorcalls;
/**
* Demonstrate warnings introduced with JDK 21 Early Access Update b15.
*/
public class ConstructorCallsDemonstration extends ParentWithAbstractMethod
{
public ConstructorCallsDemonstration()
{
overridableInitializer();
privateInitializer();
finalInitializer();
initializeCustomLogic();
}
/**
* A child class CAN override this method called by constructor
* and will trigger "this-escape" {@code -Xlint} warning.
*/
protected void overridableInitializer()
{
}
/**
* A child class cannot override this method called by constructor
* and will NOT trigger "this-escape" {@code -Xlint} warning.
*/
private void privateInitializer()
{
}
/**
* A child class cannot override this method called by constructor
* and will NOT trigger "this-escape" {@code -Xlint} warning.
*/
protected final void finalInitializer()
{
}
@Override
protected void initializeCustomLogic()
{
}
}
</pre>
<p>When the above code is compiled with <code>javac -Xlint</code>, the new warnings are seen:</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6zGt0883cUN10984jKuaZI96V07GP9MplqU4w9wvVtnTnuoPI4JVMyVhe1K3Ry4AwPGENirC-pBf1U5GOKZ-yGLtKccV3Y4kTVO93-naucPb-qB8UUg_0ktxIV_qDm2l5hP2cSxrRV2GHhlECselPcs45pC3Yl2hO0Sr7euXx5u9usLJb--fJlrbc/s1107/20230327-newXlintWarningForCtorInvokingOverridableMethods.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="387" data-original-width="1107" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6zGt0883cUN10984jKuaZI96V07GP9MplqU4w9wvVtnTnuoPI4JVMyVhe1K3Ry4AwPGENirC-pBf1U5GOKZ-yGLtKccV3Y4kTVO93-naucPb-qB8UUg_0ktxIV_qDm2l5hP2cSxrRV2GHhlECselPcs45pC3Yl2hO0Sr7euXx5u9usLJb--fJlrbc/s320/20230327-newXlintWarningForCtorInvokingOverridableMethods.png"/></a></div>
<p>The command "<code><b>javac <span style="background-color: yellow;">-Xlint</span> -sourcepath src -d classes src\dustin\examples\constructorcalls\*.java</b></code>" generates this output:</p>
<pre name="code" class="text" style="overflow: auto;">
src\dustin\examples\constructorcalls\ConstructorCallsDemonstration.java:10: warning: [this-escape] possible 'this' escape before subclass is fully initialized
overridableInitializer();
^
src\dustin\examples\constructorcalls\ParentWithAbstractMethod.java:10: warning: [this-escape] possible 'this' escape before subclass is fully initialized
initializeCustomLogic();
^
2 warnings
</pre>
<p>Executing the two code snippets shown above results in several observations:</p>
<ul>
<li>An <code>abstract</code> method called from a constructor will lead to the new <code>-Xlint this-escape</code> warning.</li>
<li>A concrete method that is <em>overridable</em> (not <code>private</code> or <code>final</code>) and called from a constructor will lead to the new <code>-Xlint this-escape</code> warning.</li>
<li>A <code>final</code> method will not cause the <code>-Xlint this-escape</code> warning to appear because sub-classes cannot override a <code>final</code> method.</li>
<li>A <code>private</code> method will not cause the <code>-Xlint this-escape</code> warning to appear because sub-classes cannot override (or even "see") a <code>private</code> method.</li>
</ul>
<p>The <a href="https://bugs.openjdk.org/browse/JDK-8299995" target="_blank">associated CSR</a> points out that just the new <code><b>-Xlint this-escape</b></code> warning can be enabled when running <code><b>javac</b></code> by specifying <code><b>-Xlint:this-escape</b></code> and this warning can be suppressed by applying the annotation <code><b>@SuppressWarnings("this-escape")</b></code> to the code for which the new warning should be suppressed.</p><div class="blogger-post-footer"><p>Original posting available at <a href="http://marxsoftware.blogspot.com/">http://marxsoftware.blogspot.com/</a> (Inspired by Actual Events)</p></div>@DustinMarxhttp://www.blogger.com/profile/10790950138196529391noreply@blogger.com0tag:blogger.com,1999:blog-6517450204508339514.post-31722202436358181862021-09-27T07:59:00.011-06:002021-09-27T07:59:00.250-06:00More Frequent Java Long-Term Releases<p>A little over four years ago, <a href="https://mreinhold.org/" target="_blank">Mark Reinhold</a> (Chief Architect of the Java Platform Group at <a href="https://oracle.com/" target="_blank">Oracle</a>) stated in his blog post "<a href="https://mreinhold.org/blog/forward-faster" target="_blank">Moving Java Forward Faster</a>": "For Java to remain competitive it must not just continue to move forward — it must move forward faster." In that post, Reinhold proposed "that after Java 9 we adopt a strict, time-based model with a new feature release every six months, update releases every quarter, and a long-term support release every three years." Reinhold stated that the motivation for this was that Java "must move forward faster ... for Java to remain competitive." Recently, a little over four years since the "<a href="https://mreinhold.org/blog/forward-faster" target="_blank">Moving Java Forward Faster</a>" post, Reinhold has posted "<a href="https://mreinhold.org/blog/forward-even-faster" target="_blank">Moving Java Forward <b>Even</b> Faster</a>."</p>
<p>Mark Reinhold's proposal in "<a href="https://mreinhold.org/blog/forward-even-faster" target="_blank">Moving Java Forward Even Faster</a>" is to "ship an LTS release every <b>two years</b>" instead of shipping a <b>long-term support</b> (LTS) release every <b>three years</b> as has been done since the 2017 proposal was implemented. Reinhold adds, "This change will give both enterprises, and their developers, more opportunities to move forward" and "will also increase the attractiveness of the non-LTS feature releases."</p>
<p>In the "<a href="https://mreinhold.org/blog/forward-even-faster" target="_blank">Moving Java Forward Even Faster</a>" post, Reinhold explains the motivation for reducing the time between LTS releases from three years to two years: "Developers are excited about the new features — which is great! Many are frustrated, however, that they cannot use them right away since their employers are only willing to deploy applications on LTS releases, which only ship once every three years."</p>
<p>Reinhold posted a <a href="https://mail.openjdk.java.net/pipermail/discuss/2021-September/005945.html" target="_blank">similar message</a> to the <a href="https://mail.openjdk.java.net/mailman/listinfo/discuss" target="_blank">OpenJDK general discussion mailing list</a>. In that message, he points out that "the LTS release following JDK 17 would thus be <b>JDK 21</b> (in <b>2023</b>), rather than <b>JDK 23</b> (in <b>2024</b>)." Reinhold also points out, "This change would, if accepted, have no effect on the main-line feature releases developed in the <a href="https://openjdk.java.net/projects/jdk/" target="_blank">JDK Project</a>. Every such release is intended to be stable and ready for production use, <a href="https://mail.openjdk.java.net/pipermail/jdk-dev/2021-May/005543.html" target="_blank">whether it's an LTS release or not</a>."</p>
<p>Reinhold concludes his <a href="https://mail.openjdk.java.net/pipermail/discuss/2021-September/005945.html" target="_blank">message</a> with a request for feedback via comments and questions. There have already been some interesting responses:</p>
<ul>
<li><a href="https://mail.openjdk.java.net/pipermail/discuss/2021-September/005950.html" target="_blank">Volker Simonis has replied</a> on behalf of the <a href="https://marxsoftware.blogspot.com/2018/11/amazon-corretto-no-cost-jdk.html" target="_blank">Amazon Corretto</a> team: "I'd like to express our support for the new JDK LTS release cadence proposal. We think this is the right step forward to keep the OpenJDK project vibrant and relevant
with benefits for both developers and enterprises."</li>
<li><a href="https://mail.openjdk.java.net/pipermail/discuss/2021-September/005954.html" target="_blank">Martijn Verburg has replied</a> on behalf of the Microsoft Java Engineering Team: "We would also like to endorse the 2-year LTS proposal for builds of OpenJDK. Since most of the end-user ecosystem prefers to have the extra stability of an LTS, this is a great way to encourage them with their modernization efforts!"</li>
<li><a href="https://mail.openjdk.java.net/pipermail/discuss/2021-September/005955.html" target="_blank">Gil Tene has replied</a> on behalf of Azul: "I'd like to express our strong support for this proposal to
move to a more frequent LTS cadence in OpenJDK."
<ul>
<li>Tene adds, "It does come with an extra maintenance burden for the community as a whole, but that burden is well worth it in our opinion."</li>
</ul>
</li>
<li><a href="https://mail.openjdk.java.net/pipermail/discuss/2021-September/005956.html" target="_blank">Andrew Hale of RedHat replied</a>: "So, from me it's a rather nervous yes, but." Hale discussed why the decision was "nuanced" and depends on the perspective taken:
<ul>
<li>"As developers of Java as well as users of it, we're perhaps biased in favour of new features, and we're less likely to feel the adverse effects of the upgrade treadmill."</li>
<li>"From my point of view as an engineer, moving to a two-year LTS cycle is broadly positive."</li>
<li>"Certifying libraries to run on a new Java release can take months of effort, and no-one is going to welcome having to do so more frequently."</li>
<li>"Many of our end users have been highly resistant to upgrading to new Java releases."</li>
</ul>
</li>
<li><a href="https://mail.openjdk.java.net/pipermail/discuss/2021-September/005946.html" target="_blank">Rémi Forax has replied</a>: "I've discussed with quite a lot of people during this week, most of them prefer a 2 year schedule for a LTS. 2 years is good for application developers, 3 years is better for library maintainers. There is at least 10x more application developers."</li>
</ul>
<p>The <a href="https://www.oracle.com/java/technologies/java-se-support-roadmap.html" target="_blank">Oracle Java SE Support Roadmap</a> has been updated to reflect the two-year candence for LTS releases. It now states (I added the <b>emphasis</b>), "Oracle will designate only certain releases as <b>Long-Term-Support</b> (LTS) releases. Java SE <b>7</b>, <b>8</b>, <b>11</b> and <b>17</b> are LTS releases. Oracle intends to make future LTS releases every two years meaning the next planned LTS release is <b>Java 21</b> in <b>September 2023</b>."</p>
<p>As a developer who uses the latest JDK releases for personal projects (and often even "plays" with the <a href="https://jdk.java.net/18/" target="_blank">OpenJDK Early-Access Builds</a>) and then deals with the frustration of using older versions of the JDK on different projects in my "day jobs," I believe that reducing the wait between LTS releases from three years to two years will be welcome.</p>
<p><strong>Related Resources</strong></p>
<ul>
<li><a href="https://mail.openjdk.java.net/pipermail/discuss/2021-September/005945.html" target="_blank">Accelerating the JDK LTS release cadence</a></li>
<li><a href="https://blogs.oracle.com/java/post/moving-the-jdk-to-a-two-year-lts-cadence" target="_blank">Moving the JDK to a Two Year LTS Cadence</a></li>
<li><a href="https://www.oracle.com/java/technologies/java-se-support-roadmap.html" target="_blank">Oracle Java SE Support Roadmap</a></li>
<li><a href="https://sdtimes.com/java/java-17-released-with-updates-to-lts-schedule/" target="_blank">Java 17 released with updates to LTS schedule</a></li>
</ul>
<div class="blogger-post-footer"><p>Original posting available at <a href="http://marxsoftware.blogspot.com/">http://marxsoftware.blogspot.com/</a> (Inspired by Actual Events)</p></div>@DustinMarxhttp://www.blogger.com/profile/10790950138196529391noreply@blogger.com0tag:blogger.com,1999:blog-6517450204508339514.post-33087575082428434282021-09-25T12:19:00.001-06:002021-09-25T19:11:45.776-06:00JDK 18: Code Snippets in Java API Documentation<p><a href="https://jdk.java.net/18/" target="_blank">OpenJDK 18 Early-Access Build</a> <b>16 (2021/9/23)</b> is now available and includes the implementation for <a href="https://openjdk.java.net/jeps/413" target="_blank">JEP 413</a> ("<b>Code Snippets in Java API Documentation</b>"), which is <a href="https://mail.openjdk.java.net/pipermail/jdk-dev/2021-September/005989.html" target="_blank">targeted for JDK 18</a>. The objective of <a href="https://openjdk.java.net/jeps/413" target="_blank">JEP 413</a> is to "introduce an <code>@snippet</code> tag for JavaDoc's Standard Doclet, to simplify the inclusion of example source code in API documentation" and the JEP itself covers the syntax of and features supported by the Javadoc <code><b>{@snippet}</b></code> tag.</p>
<p>JEP 413 introduces the new <code><b>{@snippet }</b></code> Javadoc tag:</p>
<blockquote>We introduce a new inline tag, <code>{@snippet ...}</code>, to declare code fragments to appear in the generated documentation. It can be used to declare both inline snippets, where the code fragment is included within the tag itself, and external snippets, where the code fragment is read from a separate source file.</blockquote>
<p>The JEP has far more details on what is supported by <code><b>{@snippet }</b></code> and what its syntax is. This post provides a small taste of what <code><b>{@snippet }</b></code> brings to Javadoc-based documentation and the code listings included in this post are available on <a href="https://github.com/dustinmarx/javademos/tree/master/src/dustin/examples/jdk18/javadoc" target="_blank">GitHub</a>.</p>
<p>This first contrived code listing makes use of <code><b>{@snippet }</b></code>:</p>
<pre name="code" class="java">
package dustin.examples.jdk18.javadoc;
/**
* Demonstrates {@code @snippet} Javadoc tag targeted for JDK
* as part of JEP 413 (AKA Bug JDK-8201533):
* <ul>
* <li>https://openjdk.java.net/jeps/413</li>
* <li>https://bugs.openjdk.java.net/browse/JDK-8201533</li>
* </ul>
*
* An instance of this class is obtained via my {@link #newInstance()} method
* rather than via a constructor.
*
* {@snippet :
* final SnippetExample instance = SnippetExample.newInstance(); // @highlight substring="newInstance"
* instance.processIt();
* }
*/
public class SnippetExample
{
/**
* No-arguments constructor not intended for public use.
* Use {@link #newInstance()} instead to get an instance of me:
* {@snippet :
* final SnippetExample instance = SnippetExample.newInstance(); // @highlight substring="newInstance"
* }
*/
private SnippetExample()
{
}
/**
* Preferred approach for obtaining an instance of me.
*
* @return Instance of me.
*/
public SnippetExample newInstance()
{
return new SnippetExample();
}
/**
* Performs valuable processing.
*/
public void processIt()
{
}
}
</pre>
<p>When the above code is run through the <a href="https://docs.oracle.com/en/java/javase/17/javadoc/javadoc.html#GUID-7A344353-3BBF-45C4-8B28-15025DDCC643" target="_blank">javadoc tool</a> with the <code><b>-private</b></code> option, code snippets are generated in the HTML for the class and no-arguments constructor. Note also that the "highlighted" sections have <b>bold</b> emphasis in the generated HTML.</p>
<p>Generated class-level documentation with snippet:</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-bYBMUiWhxuA/YU_BwHc4cYI/AAAAAAAASBk/MC0sPlZoifYhb8VbuA1fjmR7GDIXbI5NgCLcBGAsYHQ/s859/20210925-SnippetsClassJavadocTop.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="612" data-original-width="859" src="https://1.bp.blogspot.com/-bYBMUiWhxuA/YU_BwHc4cYI/AAAAAAAASBk/MC0sPlZoifYhb8VbuA1fjmR7GDIXbI5NgCLcBGAsYHQ/s320/20210925-SnippetsClassJavadocTop.png"/></a></div>
<p>Generated method-level documentation with snippet:</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-FCWvPKzknqc/YU_BwCnq9KI/AAAAAAAASBg/CctlnM3txOwLx60gwqEIf8rqHcfIvT2nwCLcBGAsYHQ/s858/20210925-SnippetsClassJavadocMiddle.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="710" data-original-width="858" src="https://1.bp.blogspot.com/-FCWvPKzknqc/YU_BwCnq9KI/AAAAAAAASBg/CctlnM3txOwLx60gwqEIf8rqHcfIvT2nwCLcBGAsYHQ/s320/20210925-SnippetsClassJavadocMiddle.png"/></a></div>
<p>One area where I think the <code><b>{@snippet }</b></code> may be particularly useful is in <em>package</em> documentation. A code example of use for a package description is shown in the next code listing for <code><b>package-info.java</b></code>.</p>
<pre name="code" class="java">
/**
* Examples and demonstrations of Javadoc-related capabilities.
*
* The main entrypoint for the snippets example is the {@link SnippetExample} class:
* {@snippet :
* final SnippetExample instance = SnippetExample.newInstance(); // @highlight substring="SnippetExample" @link substring="SnippetExample.newInstance()" target="SnippetExample#newInstance()"
* }
*/
package dustin.examples.jdk18.javadoc;
</pre>
<p>The generated HTML output for this package-level documentation is shown in the next screenshot.</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-kyHZRlxvICg/YU_CVntdfPI/AAAAAAAASBw/oJpT8KS15x41XTFBW04jBoJEzdpa2A4awCLcBGAsYHQ/s1844/20210925-javadoc-package.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="373" data-original-width="1844" src="https://1.bp.blogspot.com/-kyHZRlxvICg/YU_CVntdfPI/AAAAAAAASBw/oJpT8KS15x41XTFBW04jBoJEzdpa2A4awCLcBGAsYHQ/s320/20210925-javadoc-package.png"/></a></div>
<p>One of the challenges in including code snippets in Javadoc-based documentation has been that the tags used to present the code (such as <code><pre></code>, <code><code></code>, and <code>{@code}</code>) can make the Javadoc comment less readable when viewed in source directly instead of via the generated HTML. The <code><b>{@snippet }</b></code> Javadoc tag can make the code presentation better for the generated HTML while being less distracting in the source code itself. JEP 413 addresses the shortcomings of current approaches for including code snippets in Javadoc and summarizes how <code><b>{@snippet }</b></code> addresses those shortcomings:</p>
<blockquote>A better way to address all these concerns is to provide a new tag with metadata that allows the author to implicitly or explicitly specify the kind of the content so that it can be validated and presented in an appropriate manner. It would also be useful to allow fragments to be placed in separate files that can be directly manipulated by the author's preferred editor.</blockquote>
<p><a href="https://openjdk.java.net/jeps/413" target="_blank">JEP 413</a> contains far more details on application of <code><b>{@snippet }</b></code>, including the ability to reference code contained in external files.</p><div class="blogger-post-footer"><p>Original posting available at <a href="http://marxsoftware.blogspot.com/">http://marxsoftware.blogspot.com/</a> (Inspired by Actual Events)</p></div>@DustinMarxhttp://www.blogger.com/profile/10790950138196529391noreply@blogger.com0tag:blogger.com,1999:blog-6517450204508339514.post-67213350978057152062021-09-17T17:50:00.004-06:002021-09-20T08:05:53.725-06:00Java's Optional Does Not Supplant All Traditional if-null-else or if-not-null-else Checks<p><a href="https://www.baeldung.com/java-optional" target="_blank">Java</a>'s addition of <a href="https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/util/Optional.html" target="_blank">java.util.Optional</a> has been welcome and had led to more fluent code for methods that cannot always <a href="https://marxsoftware.blogspot.com/2018/01/single-jdk8-optional-return.html" target="_blank">return</a> non-<code>null</code> values. Unfortunately, <a href="https://dzone.com/articles/optional-in-java" target="_blank">Optional</a> has been <a href="https://blog.indrek.io/articles/misusing-java-optional/" target="_blank">abused</a> and one type of abuse has been overuse. I occasionally have run across code that makes use of <a href="https://blogs.oracle.com/javamagazine/post/12-recipes-for-using-the-optional-class-as-its-meant-to-be-used" target="_blank">Optional</a> when there is no clear advantage over using <code>null</code> directly.</p>
<p>A <a href="https://www.merriam-webster.com/dictionary/red-flag" target="_blank">red flag</a> that can tip off when <code>Optional</code> is being used for no advantage over checking for <code>null</code> directly is when calling code employs <a href="https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/util/Optional.html#ofNullable%28T%29" target="_blank">Optional.ofNullable(T)</a> against the returned value from the method it has just invoked. As with all "<a href="https://marxsoftware.blogspot.com/2013/06/common-red-flags-in-java-development.html" target="_blank">red</a> <a href="https://marxsoftware.blogspot.com/2013/12/more-common-red-flags-in-java.html" target="_blank">flags</a>," this doesn't mean it's necessarily a bad thing to pass the returned value from a method to <code>Optional.ofNullable(T)</code> (in fact, it is necessary to pass to APIs expecting <code>Optional</code>), but it is common for this approach to be used to provide no real value over using the returned value directly and checking it for <code>null</code>.</p>
<p>Before <a href="https://dzone.com/articles/using-optional-correctly-is-not-optional" target="_blank">Optional</a> was available, code to check for <code>null</code> returned from a method and acting one way for <code>null</code> response and another way for non-<code>null</code> response is shown next (all code snippets in this post are <a href="https://github.com/dustinmarx/javademos/blob/master/src/dustin/examples/optionalabuse/UnnecessaryOptionalDemonstrations.java" target="_blank">available on GitHub</a>).</p>
<pre name="code" class="java">
/**
* Demonstrates approach to conditional based on {@code null} or
* not {@code null} that is traditional pre-{@link Optional} approach.
*/
public void demonstrateWithoutOptional()
{
final Object returnObject = methodPotentiallyReturningNull();
if (returnObject == null)
{
out.println("The returned Object is null.");
}
else
{
out.println("The returned object is NOT null: " + returnObject);
// code processing non-null return object goes here ...
}
}
</pre>
<p>For this basic conditional, it's rarely necessary to involve <code>Optional</code>. The next code snippet is representative of the type of code I've occassionally seen when the developer is trying to replace the explicit <code>null</code> detection with use of <a href="https://www.deadcoderising.com/2015-10-06-java-8-removing-null-checks-with-optional/" target="_blank">Optional</a>:</p>
<pre name="code" class="java">
/**
* Demonstrates using {@link Optional} in exactly the manner {@code null}
* is often used (conditional on whether the returned value is empty or
* not versus on whether the returned value is {@code null} or not).
*/
public void demonstrateOptionalUsedLikeNullUsed()
{
final Optional<Object> optionalReturn
= Optional.ofNullable(methodPotentiallyReturningNull());
if (optionalReturn.isEmpty())
{
out.println("The returned Object is empty.");
}
else
{
out.println("The returned Object is NOT empty: " + optionalReturn);
// code processing non-null return object goes here ...
}
}
</pre>
<p>The paradigm in this code is essentially the same as the traditional <code>null</code>-checking code, but uses <a href="https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/util/Optional.html#isEmpty%28%29" target="_blank">Optional.isEmpty()</a> to perform the same check. This approach does not add any readability or other advantage but does come at a small cost of an additional object instantiation and method call.</p>
<p>A variation of the above use of <code>Optional</code> is to use its <a href="https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/util/Optional.html#ifPresent%28java.util.function.Consumer%29" target="_blank">ifPresent(Consumer)</a> method in conjunction with its <a href="https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/util/Optional.html#isEmpty%28%29" target="_blank">isEmpty()</a> method to form the same basic logic of doing one thing if the returned value is present and another thing if the returned value is empty. This is demonstrated in the following code.</p>
<pre name="code" class="java">
/**
* Demonstrates using {@link Optional} methods {@link Optional#ifPresent(Consumer)}
* and {@link Optional#isEmpty()} in similar manner to traditional condition based
* on {@code null} or not {@code null}.
*/
public void demonstrateOptionalIfPresentAndIsEmpty()
{
final Optional<Object> optionalReturn
= Optional.ofNullable(methodPotentiallyReturningNull());
optionalReturn.ifPresent(
(it) -> out.println("The returned Object is NOT empty: " + it));
if (optionalReturn.isEmpty())
{
out.println("The returned object is empty.");
}
}
</pre>
<p>This code appears bit shorter than the traditional approach of checking the returned value directly for <code>null</code>, but still comes at the cost of an extra object instantiation and requires two method invocations. Further, it just feels a bit weird to check first if the <a href="https://nipafx.dev/design-java-optional/" target="_blank">Optional</a> is present and then immediately follow that with a check if it's empty. Also, if the logic that needed to be performed was more complicated than writing out a message to standard output, this approach becomes less wieldy.</p>
<p><b>Conclusion</b></p>
<p>Code that handles a method's return value and needs to do one thing if the returned value is <code>null</code> and do another thing if the returned value is <em>not</em> <code>null</code> will rarely enjoy any advantage of wrapping that returned value in <code>Optional</code> simply to check whether it's present or empty. The wrapping of the method's returned value in an <code>Optional</code> is likely only worth the costs if that <code>Optional</code> is used within fluent chaining or APIs that work with <code>Optional</code>.</p><div class="blogger-post-footer"><p>Original posting available at <a href="http://marxsoftware.blogspot.com/">http://marxsoftware.blogspot.com/</a> (Inspired by Actual Events)</p></div>@DustinMarxhttp://www.blogger.com/profile/10790950138196529391noreply@blogger.com6tag:blogger.com,1999:blog-6517450204508339514.post-26785423039748459142021-09-15T22:53:00.004-06:002021-09-20T08:08:40.919-06:00The Case of the Missing JEPs<p>The <a href="https://openjdk.java.net/jeps/1" target="_blank">JDK Enhancement-Proposal</a> (<a href="https://cr.openjdk.java.net/~mr/jep/jep-2.0-02.html" target="_blank">JEP</a>) process is "for collecting, reviewing, sorting, and recording the results of proposals for enhancements to the JDK and for related efforts, such as process and infrastructure improvements." <a href="http://openjdk.java.net/jeps/0" target="_blank">JEP 0</a> is the "JEP Index" of "all JDK Enhancement Proposals, known as JEPs." This post provides a brief overview of current JDK Enhancement Proposals and discusses the surprisingly mysterious disappearance of two JEPs (<b>JEP 187</b> and <b>JEP 145</b>).</p>
<p><b style="font-size: 110%;">JDK Enhancement Proposal Overview</b></p>
<p>The JEPs in the <a href="https://openjdk.java.net/jeps/0" target="_blank">JEP Index</a> with single-digit numbers are "<b>Process</b>" type JEPs and are currently:</p>
<ul>
<li><a href="https://openjdk.java.net/jeps/1" target="_blank">JEP 1: JDK Enhancement-Proposal & Roadmap Process</a></li>
<li><a href="https://openjdk.java.net/jeps/2" target="_blank">JEP 2: JEP Template</a></li>
<li><a href="https://openjdk.java.net/jeps/3" target="_blank">JEP 3: JDK Release Process</a></li>
</ul>
<p>The JEPs in the <a href="http://openjdk.java.net/jeps/0" target="_blank">JEP Index</a> with two-digit numbers are "<b>Informational</b>" type JEPs are are currently:</p>
<ul>
<li><a href="https://openjdk.java.net/jeps/11" target="_blank">JEP 11: Incubator Modules</a></li>
<li><a href="https://openjdk.java.net/jeps/12" target="_blank">JEP 12: Preview Features</a></li>
</ul>
<p>The remainder of the listed JEPs (with three-digit numbers) in the <a href="https://openjdk.java.net/jeps/0" target="_blank">JEP Index</a> are "<b>Feature</b>" type JEPs and currently range in number from <a href="https://openjdk.java.net/jeps/101" target="_blank">JEP-101</a> ("Generalized Target-Type Inference") through <a href="https://openjdk.java.net/jeps/418" target="_blank">JEP 418</a> ("Internet-Address Resolution SPI") (new <em>candidate</em> JEP <a href="https://mail.openjdk.java.net/pipermail/jdk-dev/2021-September/005990.html" target="_blank">as of this month</a> [September 2021]).</p>
<p>Finally, there are some JEPs that do not yet have JEP numbers and which are shown in the under the heading "<a href="https://openjdk.java.net/jeps/0#Draft-and-submitted-JEPs" target="_blank">Draft and submitted JEPs</a>" The JEPs in this state do not yet have their own JEP numbers, but instead are listed with a number in the <a href="https://bugs.openjdk.java.net/secure/Dashboard.jspa" target="_blank">JDK Bug System</a> (JBS).</p>
<p>Originally, a JEP could exist in one of several different "JEP 1 <a href="https://openjdk.java.net/jeps/1#Process-states" target="_blank">Process States</a>":</p>
<ul>
<li>Draft</li>
<li>Posted</li>
<li>Submitted</li>
<li>Candidate</li>
<li>Funded</li>
<li>Completed</li>
<li>Withdrawn</li>
<li>Rejected</li>
<li>Active</li>
</ul>
<p>The explanation of evolved potential JEP states is described in "<a href="https://cr.openjdk.java.net/~mr/jep/jep-2.0-02.html" target="_blank">JEP draft: JEP 2.0, draft 2</a>." This document has a "<b>Workflow</b>" section that states that the "revised JEP Process has the following states and transitions for Feature and Infrastructure JEPs" and shows a <a href="https://cr.openjdk.java.net/~mr/jep/jep-2.0-fi.png" target="_blank">useful graphic of these workflows</a>. This document also describes the states of a <b>Feature</b> JEP:</p>
<ul>
<li>Draft</li>
<li>Submitted</li>
<li>Candidate</li>
<li>Proposed to Target</li>
<li>Targeted</li>
<li>Integrated</li>
<li>Complete</li>
<li>Closed/Delivered</li>
<li>Closed/Rejected</li>
<li>Proposed to Drop</li>
</ul>
<p>Neither these documented states for <b>Feature</b> JEPs nor the additional text that describes these state transitions describes a JEP with a JEP number (rather than a JBS number) being completely removed and this is what makes the disappearance of <a href="https://mail.openjdk.java.net/pipermail/core-libs-dev/2014-January/024374.html" target="_blank">JEP 187</a> ("Serialization 2.0") and <a href="https://mail.openjdk.java.net/pipermail/hotspot-dev/2012-February/005335.html" target="_blank">JEP 145</a> ("Cache Compiled Code") unexpected.</p>
<p> </p>
<p><b style="font-size: 110%;">The Disappearance of JEP 187 ("Serialization 2.0")</b></p>
<p><b>JEP 187</b> is not listed in the <a href="http://openjdk.java.net/jeps/0" target="_blank">JEP Index</a>, but we have the following evidence that it did exist at one time:</p>
<ul>
<li><a href="https://mail.openjdk.java.net/pipermail/core-libs-dev/2014-January/024374.html" target="_blank">Original message</a> on OpenJDK <a href="https://mail.openjdk.java.net/mailman/listinfo/core-libs-dev" target="_blank">core-libs-dev mailing list</a> (14 January 2014)</li>
<li><a href="https://marxsoftware.blogspot.com/2009/10/internet-archive-wayback-machine.html" target="_blank">Internet Archive Wayback Machine</a>
<ul>
<li><a href="https://web.archive.org/web/20140624144539/https://openjdk.java.net/jeps/187" target="_blank">24 June 2014 14:45:39</a></li>
<li><a href="https://web.archive.org/web/20140702193924/https://openjdk.java.net/jeps/187" target="_blank">2 July 2014 19:39:24</a></li>
</ul>
</li>
<li>Mercurial Changesets
<ul>
<li><a href="https://hg.openjdk.java.net/jep/jeps/rev/b2f990fa2dde" target="_blank">OpenJDK / jep / jeps changeset 194:b2f990fa2dde: 187: Serialization 2.0</a> (13 January 2014)</li>
<li><a href="https://hg.openjdk.java.net/jep/jeps/rev/5f24c115b6e6" target="_blank">OpenJDK / jep / jeps changeset 65:5f24c115b6e6 154: Remove Serialization</a> (1 April 2012)</li>
</ul>
</li>
</ul>
<p>It's surprisingly difficult to find any explanation for what happened to <b>JEP 187</b>. Unlike fellow serialization-related <a href="https://openjdk.java.net/jeps/154" target="_blank">JEP 154</a> ("Remove Serialization") which has been moved to status "Closed / Withdrawn", JEP 187 appears to have been removed completely rather than being present with a "Closed / Withdrawn" status or "Closed / Rejected" status. Adding to the suspicious circumstances surrounding <b>JEP 187</b>, two requests on OpenJDK mailing lists regarding the state of this JEP (<a href="http://mail.openjdk.java.net/pipermail/core-libs-dev/2014-December/030505.html" target="_blank">14 December 2014 on core-libs-dev</a> and <a href="https://mail.openjdk.java.net/pipermail/jdk-dev/2021-September/005991.html" target="_blank">6 September 2021 on jdk-dev</a>) have so far gone unanswered.</p>
<p>The reasons for the complete disappearance of <b>JEP 187</b> can be insuated from reading the "exploratory document" titled "<a href="https://cr.openjdk.java.net/~briangoetz/amber/serialization.html" target="_blank">Towards Better Serialization</a>" (June 2019). I also previously touched on this in my post "<a href="https://marxsoftware.blogspot.com/2018/06/future-of-java-serialization.html" target="_blank">JDK 11: Beginning of the End for Java Serialization?</a>"</p>
<p> </p>
<p><b style="font-size: 110%;">The Disapperance of JEP 145 ("Cache Compiled Code")</b></p>
<p>Like JEP 187, <b>JEP-145</b> is not listed in the <a href="http://openjdk.java.net/jeps/0" target="_blank">JEP Index</a>, but there is evidence that it did exist at one time:</p>
<ul>
<li><a href="https://mail.openjdk.java.net/pipermail/hotspot-dev/2012-February/005335.html" target="_blank">Original message</a> on OpenJDK <a href="https://mail.openjdk.java.net/mailman/listinfo/hotspot-dev" target="_blank">hotspot-dev mailing list</a> (28 February 2012)</li>
<li><a href="https://twitter.com/openjdk/status/174648974618263552?lang=en" target="_blank">28 February 2012 Tweet</a></li>
<li>Internet Archive Wayback Machine
<ul>
<li><a href="https://web.archive.org/web/20140505001804/https://openjdk.java.net/jeps/145" target="_blank">5 May 2014 00:18:04</a></li>
</ul>
</li>
<li><a href="https://hg.openjdk.java.net/jep/jeps/raw-file/c915dfb4117d/jep-145.md" target="_blank">Mercurial Source</a>
<ul>
<li><a href="http://hg.openjdk.java.net/jep/jeps/rev/a16daa94ba0f" target="_blank">OpenJDK / jep / jeps changeset 54:a16daa94ba0f</a> (28 February 2012)</li>
</ul>
</li>
</ul>
<p>Also similarly to JEP 187, it is surprisingly difficult to find explanations for the removal of <b>JEP 145</b>. There is a <a href="https://stackoverflow.com/questions/39394819/what-happened-to-jep-145-faster-jvm-startup-due-to-compiled-code-reusage" target="_blank">StackOverflow question about its fate</a>, but the <a href="https://stackoverflow.com/a/40309509" target="_blank">responses are mostly speculative</a> (but possible).</p>
<p>The most <a href="https://stackoverflow.com/questions/1992486/why-doesnt-the-jvm-cache-jit-compiled-code#comment116965657_20859066" target="_blank">prevalent speculation</a> regarding the disappearance of <b>JEP 145</b> is that it <a href="https://stackoverflow.com/a/40309509" target="_blank">is not needed due</a> to <a href="https://www.graalvm.org/reference-manual/compiler/#ahead-of-time-compilation" target="_blank">Ahead-of-Time</a> (<a href="https://openjdk.java.net/jeps/295" target="_blank">AOT</a>) compilation.</p>
<p> </p>
<p><b style="font-size: 110%;">Conclusion</b></p>
<p>It seems that <b><a href="https://mail.openjdk.java.net/pipermail/core-libs-dev/2014-January/024374.html" target="_blank">JEP 187</a></b> ("Serialization 2.0") and <b><a href="https://mail.openjdk.java.net/pipermail/hotspot-dev/2012-February/005335.html" target="_blank">JEP 145</a></b> ("Cache Compiled Code") have both been rendered obsolete by changing developments, but it is surprising that they've vanished completely from the <a href="http://openjdk.java.net/jeps/0" target="_blank">JEP Index</a> rather than being left intact with a closed or withdrawn state.</p>
<div class="blogger-post-footer"><p>Original posting available at <a href="http://marxsoftware.blogspot.com/">http://marxsoftware.blogspot.com/</a> (Inspired by Actual Events)</p></div>@DustinMarxhttp://www.blogger.com/profile/10790950138196529391noreply@blogger.com0tag:blogger.com,1999:blog-6517450204508339514.post-31997474072163130292021-09-09T20:23:00.000-06:002021-09-09T20:23:18.871-06:00Surprisingly High Cost of Java Variables with Capitalized Names<p>I've read hundreds of thousands or perhaps even millions of lines of Java code during my career as I've worked with my projects' baselines; read code from open source libraries I use; and read code examples in blogs, articles, and books. I've seen numerous different conventions and styles represented in the wide variety of Java code that I've read. However, in the vast majority of cases, the Java developers have used capitalized identifiers for classes, enums and other types and used camelcase identifiers beginning with a lowercase letter for local and other types of variables (fields used as constants and <code>static</code> fields have sometimes had differening naming conventions). Therefore, I was really surprised recently when I was reading some Java code (not in my current project's baseline thankfully) in which the author of the code had capitalized both the types and the identifiers of the local variables used in that code. What surprised me most is how difficult this small change in approach made reading and mentally parsing that otherwise simple code.</p>
<p>The following is a represenative example of the style of Java code that I was so surprised to run across:</p>
<p><b>Code Listing for <code>DuplicateIdentifiersDemo.java</code></b></p>
<pre name="code" class="java">
package dustin.examples.sharednames;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static java.lang.System.out;
/**
* Demonstrates ability to name variable exactly the same as type,
* despite this being a really, really, really bad idea.
*/
public class DuplicateIdentifiersDemo
{
/** "Time now" at instantiation, measured in milliseconds. */
private final static long timeNowMs = new Date().getTime();
/** Five consecutive daily instances of {@link Date}. */
private final static List<Date> Dates = List.of(
new Date(timeNowMs - TimeUnit.DAYS.toMillis(1)),
new Date(timeNowMs),
new Date(timeNowMs + TimeUnit.DAYS.toMillis(1)),
new Date(timeNowMs + TimeUnit.DAYS.toMillis(2)),
new Date(timeNowMs + TimeUnit.DAYS.toMillis(3)));
public static void main(final String[] arguments)
{
String String;
final Date DateNow = new Date(timeNowMs);
for (final Date Date : Dates)
{
if (Date.before(DateNow))
{
String = "past";
}
else if (Date.after(DateNow))
{
String = "future";
}
else
{
String = "present";
}
out.println("Date " + Date + " is the " + String + ".");
}
}
}
</pre>
<p>The code I encountered was only slightly more complicated than that shown above, but it was more painful for me to mentally parse than it should have been because of the naming of the local variables with the exact same names as their respective types. I realized that my years of reading and mentally parsing Java code have led me to intuitively initially think of identifiers beginning with a lowercase letter as variable names and identifiers beginning with an uppercase letter as being type identifiers. Although this type of instinctive assumption generally allows me to more quickly read code and figure out what it does, the assumption in this case was hindering me as I had to put special effort into not allowing myself to think of <em>some</em> occurrences of "String" and "Date" as variables names and occurrences as class names.</p>
<p>Although the code shown above is relatively simple code, the unusual naming convention for the variable names makes it more difficult than it should be, especially for experienced Java developers who have learned to quickly size up code by taking advantage of well-known and generally accepted coding conventions.</p>
<p><a href="https://docs.oracle.com/javase/tutorial/java/TOC.html" target="_blank">The Java Tutorials </a>section on "<a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html" target="_blank">Java Language Keywords</a>" provides the "list of keywords in the Java programming language" and points out that "you cannot use any of [the listed keywords] as identifiers in your programs." It also mentions that literals (but not keywords) <code>true</code>, <code>false</code>, and <code>null</code> also cannot be used as identifiers. Note that this list of keywords includes the primitive types such as <code>boolean</code> and <code>int</code>, but does not include identifiers of reference types such as <code>String</code>, <code>Boolean</code>, and <code>Integer</code>.</p>
<p>Because very close to all Java code that I had read previously used lowercase first letters for non-constant, non-<code>static</code> variable names, I wondered if that convention is mentioned in the Java Tutorial section on <a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html#naming" target="_blank">naming variables</a>. It is. That "<a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html" target="_blank">Variables</a>" section states: "Every programming language has its own set of rules and conventions for the kinds of names that you're allowed to use, and the Java programming language is no different. ... If the name you choose consists of only one word, spell that word in all lowercase letters. If it consists of more than one word, capitalize the first letter of each subsequent word. The names <code>gearRatio</code> and <code>currentGear</code> are prime examples of this convention."
<p><b>Conclusion</b></p>
<p>I've long been a believer in conventions that allow for more efficient reading and mental parsing of code. Running into this code with capitalized first letters for its camelcase variable name identifiers reminded me of this and has led me to believe that the greater the general acceptance of a convention for a particular language, the more damaging it is to readability to veer from that convention.</p>
<div class="blogger-post-footer"><p>Original posting available at <a href="http://marxsoftware.blogspot.com/">http://marxsoftware.blogspot.com/</a> (Inspired by Actual Events)</p></div>@DustinMarxhttp://www.blogger.com/profile/10790950138196529391noreply@blogger.com0tag:blogger.com,1999:blog-6517450204508339514.post-31110071582179980062021-03-26T16:23:00.002-06:002021-03-27T20:28:15.516-06:00Implementing equals(Object) with instanceof Pattern Matching<p><a href="https://docs.oracle.com/en/java/javase/14/language/pattern-matching-instanceof-operator.html" target="_blank">Pattern matching for the instanceof operator</a> was introduced as a <a href="http://marxsoftware.blogspot.com/2020/02/jdk14-instanceof-pattern-matching.html" target="_blank">preview feature with JDK 14</a> and was <a href="http://marxsoftware.blogspot.com/2020/08/instanceof-pattern-matching-records.html" target="_blank">finalized with JDK 16</a>. Because <a href="https://www.oracle.com/emea/news/announcement/oracle-announces-java-16-2021-03-16.html" target="_blank">instanceof pattern matching</a> is <a href="https://mail.openjdk.java.net/pipermail/amber-spec-experts/2020-August/002433.html" target="_blank">finalized</a> for <a href="https://openjdk.java.net/projects/jdk/16/" target="_blank">JDK 16</a>, it is not surprising to now see <a href="https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-March/074996.html" target="_blank">changes being made to the JDK</a> to take advantage of <a href="https://openjdk.java.net/jeps/394" target="_blank">pattern matching for the instanceof operator</a>. These changes to the JDK to leverage instanceof pattern matching can provide ideas and examples for where to begin applying this in our own code. In this post, I look at the use of <a href="https://benjiweber.co.uk/blog/2021/03/14/java-16-pattern-matching-fun/" target="_blank">instanceof pattern matching</a> in implementation of the ubiquitous <code><b>equals(Object)</b></code> methods.</p>
<p>In a <a href="https://mail.openjdk.java.net/pipermail/core-libs-dev/2021-March/075084.html" target="_blank">message posted</a> to the <a href="https://mail.openjdk.java.net/mailman/listinfo/core-libs-dev" target="_blank">core-libs-dev OpenJDK mailing list</a> related to a code review for <a href="https://bugs.openjdk.java.net/browse/JDK-8263358" target="_blank">JDK-8263358</a> ("Update java.lang to use instanceof pattern variable"), <a href="https://twitter.com/BrianGoetz" target="_blank">Brian Goetz</a> provided a reminder that a standard approach used in implementation of <code>equals(Object)</code> can now be modified to take advantage of pattern matching for <code>instanceof</code>.</p>
<p>In the message, Goetz uses an example of how we have often implemented <code>equals(Object)</code> (but using <code>instanceof</code> pattern matching in this example consistent with the past):</p>
<pre name="code" class="java">
if (!(o instanceof Key that)) return false;
return name == that.name && Arrays.equals(ptypes, that.ptypes);
</pre>
<p>Goetz points out that this can now be written with a single statement, in this manner:</p>
<pre name="code" class="java">
return (o instanceof Key that)
&& name == that.name
&& Arrays.equals(ptypes, that.ptypes);
</pre>
<p>Goetz's message concludes with this:</p>
<blockquote>The use of "if it's not, return false" is a holdover from when we couldn't express this as a single expression (which is almost always preferable), which means we had to fall back to control flow. Now we don't have to.</blockquote>
<p>A <a href="https://github.com/openjdk/jdk/commit/e9d913152cefda827e01c060a13f15eacc086b33" target="_blank">new commit</a> was made based on Goetz's feedback and that commit is <a href="https://github.com/openjdk/jdk/commit/e9d913152cefda827e01c060a13f15eacc086b33" target="_blank">Commit e9d913152cefda827e01c060a13f15eacc086b33</a>. One can review the several changes associated with this commit to see multiple statements converted into single statements in the various <code>equals(Object)</code> methods.</p>
<p>Being able to use <code>instanceof</code> pattern matching to implement <code>equals(Object)</code> with one fewer statement is a small improvement that is nevertheless welcome.</p>
<div class="blogger-post-footer"><p>Original posting available at <a href="http://marxsoftware.blogspot.com/">http://marxsoftware.blogspot.com/</a> (Inspired by Actual Events)</p></div>@DustinMarxhttp://www.blogger.com/profile/10790950138196529391noreply@blogger.com0tag:blogger.com,1999:blog-6517450204508339514.post-40876534303024025282021-02-27T22:33:00.010-07:002021-02-28T19:17:52.777-07:00Java NullPointerException Avoidance and Enhancement Tactics<p>An encountered <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/NullPointerException.html" target="_blank">NullPointerException</a> can be a useful mechanism for highlighting when a certain code flow or certain data has led to unexpected results (and the messages provided by <code>NullPointerException</code> are <a href="https://marxsoftware.blogspot.com/2020/06/better-npe-message-auto-jdk15.html" target="_blank">much improved with JDK 15</a>). However, there are other times when the presence of <code>null</code> is not an exceptional condition and for those such cases there are several tactics that can be used to easily and cleanly avoid an unwanted <code>NullPointerException</code>. Even when the occurrence of a <code>NullPointerException</code> helps identify problems, there are other tactics we can use to make the most of these opportunities.</p>
<p>The code samples featured in this post are part of class <a href="https://github.com/dustinmarx/javademos/blob/master/src/dustin/examples/nullsafe/tactics/NullSafeTactics.java" target="_blank">NullSafeTactics</a> and its full source code is <a href="https://github.com/dustinmarx/javademos/blob/master/src/dustin/examples/nullsafe/tactics/NullSafeTactics.java" target="_blank">available on GitHub</a>.</p>
<p style="font-size: 125%;">Contents</p>
<ul>
<li><a href="#elegant-unnecessary">Elegantly Avoiding Unnecessary <code>NullPointerException</code>s</a>
<ul>
<li><a href="#implicit-string-conversion">Implicit Java String Conversion</a></li>
<li><a href="#string-valueof">Null-safe String Representation with <code>String.valueOf(Object)</code></a></li>
<li><a href="#objects-tostring">Null-safe String Representation with <code>Objects.toString(Object)</code></a></li>
<li><a href="#objects-tostring-default">Null-safe String Representation with <code>Objects.toString(Object, String)</code></a></li>
<li><a href="#default-object-replacement">Default Value Replacement of <code>null</code> for Any <code>Object</code></a></li>
<li><a href="#compare-enums">Comparing enums Safely</a></li>
<li><a href="#non-null-left-side">Comparing Objects Safely with Known Non-<code>null</code> Object on LHS of <code>.equals(Object)</code></a></li>
<li><a href="#case-insensitive-string-left-side">Case Insensitive Comparison of Strings Safely with Known Non-<code>null</code> String on LHS of <code>.equals(Object)</code></a></li>
<li><a href="#objects-equals">Safely Comparing Objects When Neither is Known to be Non-<code>null</code></a></li>
<li><a href="#null-safe-hash">Null-safe Hashing</a></li>
</ul>
</li>
<li><a href="#elegant-necessary">Elegantly Handling Useful <code>NullPointerException</code>s</a>
<ul>
<li><a href="#require-non-null">Controlling When and What Related to Unexpected <code>null</code></a></li>
</ul>
</li>
<li><a href="#other">Other Null-Handling Tactics</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
<p style="font-size: 125%"><b><a name="elegant-unnecessary">Elegantly Avoiding Unnecessary <code>NullPointerException</code>s</a></b></p>
<p><b><a name="implicit-string-conversion">Implicit Java String Conversion</a></b></p>
<p>There are often times when we want the string representation of something that is potentially <code>null</code> and we do not want the access of that string representation to result in a <code>NullPointerException</code>. An example of this is when we log certain conditions and the context we include in the logged message includes a variable or field that is <code>null</code>. It is highly unlikely in such a case that we want a <code>NullPointerException</code> to be possibly thrown during the attempted logging of some potentially different condition. Fortunately, <a href="https://docs.oracle.com/javase/specs/jls/se15/html/jls-5.html#jls-5.1.11" target="_blank">Java's string conversion</a> is often available in these situations.</p>
<p>Even when the field variable <code>NULL_OBJECT</code> of type <code>Object</code> is <code>null</code>, the following code will NOT result in a <code>NullPointerException</code> thanks to Java's string conversion handling a <code>null</code> implicitly and converting it to the "null" string instead.</p>
<pre name="code" class="java">
/**
* Demonstrates that Java string conversion avoids {@link NullPointerException}.
*/
public void demonstrateNullSafeStringConversion()
{
executeOperation(
"Implicit Java String Conversion",
() -> "The value of the 'null' object is '" + NULL_OBJECT + "'.");
}
</pre>
<p>The output from running the above code snippet demonstrates that the <code>NullPointerException</code> does not get thrown.</p>
<pre style="font-size: 10pt; overflow: auto;">
Feb 25, 2021 9:26:19 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
INFO: Demonstration 'Implicit Java String Conversion' completed without exception!
</pre>
<p>The implicit Java string conversion avoided a <code>NullPointerException</code>. When <code>toString()</code> is explicitly called on that same <code>null</code>, a <code>NullPointerException</code> is encountered. This is shown in the next code listing and the output it leads to is shown after the code listing.</p>
<pre name="code" class="java">
/**
* Demonstrates that explicit {@link Object#toString()} on {@code null} leads to
* {@link NullPointerException}.
*/
public void demonstrateNullUnsafeExplicitToString()
{
executeOperation(
"Unsafe Explicit toString() Invocation on null",
() -> "The value of the 'null' object is '" + NULL_OBJECT.toString() + "'.");
}
</pre>
<pre style="font-size: 10pt; overflow: auto;">
Feb 25, 2021 9:32:06 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
SEVERE: Exception encountered while trying to run operation for demonstration 'Unsafe Explicit toString() Invocation on null': java.lang.NullPointerException: Cannot invoke "Object.toString()" because "dustin.examples.nullsafe.tactics.NullSafeTactics.NULL_OBJECT" is null
</pre>
<p>Note that these examples in this post have been executed with a JDK 17 early access release, so the <code>NullPointerException</code>s shown in this post benefit from the <a href="https://marxsoftware.blogspot.com/2019/10/better-npe-messages-in-jdk-14.html" target="_blank">better NPE messages</a> introduced with JDK 14 (and are <a href="https://marxsoftware.blogspot.com/2020/06/better-npe-message-auto-jdk15.html" target="_blank">enabled by default since JDK 15</a>).</p>
<p><b><a name="string-valueof">Null-safe String Representation with <code>String.valueOf(Object)</code></a></b></p>
<p>Allowing Java's implicit string conversion to represent <code>null</code> as the "null" string is the cleanest and easiest way to handle <code>null</code> when constructing strings. However, there are many times when we need a string representation of a Java object when implicit string conversion is not available. In such cases, <a href="https://marxsoftware.blogspot.com/2009/04/value-of-stringvalueof.html" target="_blank">String.valueOf(Object)</a> can be used to achieve functionality similar to the implicit string conversion. When an object is passed to <code>String.valueOf(Object)</code>, that method will return the results of the object's <code>toString()</code> if that object is not <code>null</code> or will return the "null" string if the object is <code>null</code>.</p>
<p>The following code listing demonstrates <code>String.valueOf(Object)</code> in action and the output from running that code is shown after the code listing.</p>
<pre name="code" class="java">
/**
* Demonstrates that {@link String#valueOf(Object)} will render {@code null} safely
* as "null" string.
*
* In many cases, use of {@link String#valueOf(Object)} is unnecessary because Java's
* string conversion will perform the same effect. {@link String#valueOf(Object)} is
* necessary when Java is not able to implicitly convert to a {@link String}.
*
* See also https://marxsoftware.blogspot.com/2009/04/value-of-stringvalueof.html.
*/
public void demonstrateNullSafeStringValueOf()
{
executeOperation(
"Null-safe String Representation with String.valueOf(Object)",
() -> "The value of the 'null' object is '" + String.valueOf(NULL_OBJECT) + "'.");
}
</pre>
<pre style="font-size: 10pt; overflow: auto;">
Feb 25, 2021 10:05:52 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
INFO: Demonstration 'Null-safe String Representation with String.valueOf(Object)' completed without exception!
</pre>
<p>There are several overloaded versions of <code>String#valueOf</code> accepting parameter types other than <code>Object</code>, but they all behave similarly.</p>
<p><b><a name="objects-tostring">Null-safe String Representation with <code>Objects.toString(Object)</code></a></b></p>
<p>The <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Objects.html" target="_blank">Objects</a> class provides several methods to allow for elegant handling of potential <code>null</code>s. One of these, <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Objects.html#toString%28java.lang.Object%29" target="_blank">Objects.toString(Object)</a> works exactly like the just-discussed <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/String.html#valueOf%28java.lang.Object%29" target="_blank">String.valueOf(Object)</a>. In fact, as described in the post "<a href="https://marxsoftware.blogspot.com/2018/08/null-safe-to-string.html" target="_blank">String.valueOf(Object) versus Objects.toString(Object)</a>", the <code>Objects.toString(Object)</code> method delegates to the <code>String.valueOf(Object)</code> method.</p>
<p>The following code listing demonstrates use of <code>Objects.toString(Object)</code> and the output from running it follows the code listing.</p>
<pre name="code" class="java">
/**
* Demonstrates that {@link Objects#toString(Object)} will render {@code null} safely
* as "null" string.
*
* In many cases, use of {@link Objects#toString(Object)} is unnecessary because Java's
* string conversion will perform the same effect. {@link Objects#toString(Object)} is
* necessary when Java is not able to implicitly convert to a {@link String}.
*/
public void demonstrateObjectsToString()
{
executeOperation(
"Null-safe String Representation with Objects.toString(Object)",
() -> "The value of the 'null' object is '" + Objects.toString(NULL_OBJECT) + "'.");
}
</pre>
<pre style="font-size: 10pt; overflow: auto;">
Feb 25, 2021 10:19:52 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
INFO: Demonstration 'Null-safe String Representation with Objects.toString(Object)' completed without exception!
</pre>
<p>I tend to use <code>String.valueOf(Object)</code> instead of <code>Objects.toString(Object)</code> because the latter calls the former anyway and because there are overloaded versions of <code>String#valueOf</code>.</p>
<p><b><a name="objects-tostring-default">Null-safe String Representation with <code>Objects.toString(Object, String)</code></a></b></p>
<p>The approaches covered so far in this post (implicit string conversion, <code>String#valueOf</code> methods, and <code>Objects.toString(Object)</code>) all result in the "null" string when a <code>null</code> is presented to them. There are times when we may prefer to have something other than the "null" string be presented as the string representation of <code>null</code>. An example of this is when we want to return an empty string from a method rather than returning <code>null</code> from a method. The following code listing demonstrates using <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Objects.html#toString%28java.lang.Object,java.lang.String%29" target="_blank">Objects.toString(Object, String)</a> to have an empty string be provided when first passed-in argument turns out to be <code>null</code>.</p>
<pre name="code" class="java">
/**
* Demonstrates that {@link Objects#toString(Object, String)} will render {@code null}
* potentially safely as the "default" string specified as the second argument.
*
* In many cases, use of {@link Objects#toString(Object, String)} is unnecessary because
* Java's string conversion will perform the same effect. {@link Objects#toString(Object)}
* is necessary when Java is not able to implicitly convert to a {@link String} or when
* it is desired that the string representation of the {@code null} be something other
* than the "null" string.
*/
public void demonstrateObjectsToStringWithDefault()
{
executeOperation(
"Null-safe String Representation with Objects.toString(Object,String) Using Empty String Default",
() -> "The value of the 'null' object is '" + Objects.toString(NULL_OBJECT, "") + "'.");
}
</pre>
<pre style="font-size: 10pt; overflow: auto;">
Feb 25, 2021 10:33:16 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
INFO: Demonstration 'Null-safe String Representation with Objects.toString(Object,String) Using Empty String Default' completed without exception!
</pre>
<p><b><a name="default-object-replacement">Default Value Replacement of <code>null</code> for Any <code>Object</code></a></b></p>
<p>The JDK-provided methods covered so far are useful for safely acquiring string representation of objects that might be <code>null</code>. Sometimes, we may want to handle a potential instance that might be <code>null</code> of a class other than <code>String</code>. In that case, the <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Objects.html#requireNonNullElse%28T,T%29" target="_blank">Objects.requireNonNullElse(T, T)</a> method allows specification of a default value that should be used if the object in question (first parameter to the method) is <code>null</code>. This is demonstrated with the following code listing and its accompanying output that follows it.</p>
<pre name="code" class="java">
/**
* Demonstrates that {@link Objects#requireNonNullElse(Object, Object)} will render
* {@code null} safely for any potential {@code null} passed to it by returning the
* supplied default instead when the object in question is {@code null}. Two
* examples are included in this method's demonstration:
* <ol>
* <li>{@code null} {@link Object} safely rendered as custom supplied default "null" string</li>
* <li>{@code null} {@link TimeUnit} safely rendered as custom supplied default {@link TimeUnit#SECONDS}</li>
* </ol>
*
* In many cases, use of {@link Objects#requireNonNullElse(Object, Object)} is not
* necessary because Java's string conversion will perform the same effect.
* {@link Objects#requireNonNullElse(Object, Object)} is necessary when Java is not
* able to implicitly convert to a {@link String} or when the potentially {@code null}
* object is not a {@link String} or when the object to have a default returned
* when it is {@code null} is of class other than {@link String}.
*/
public void demonstrateNullSafeObjectsRequireNonNullElse()
{
executeOperation(
"Null-safe String Representation with Objects.requireNonNullElse(Object, Object)",
() -> "The value of the 'null' object is '"
+ Objects.requireNonNullElse(NULL_OBJECT, "null") + "'");
executeOperation("Null-safe TimeUnit access with Objects.requireNonNullElse(Object, Object)",
() -> "The value used instead of 'null' TimeUnit is '"
+ Objects.requireNonNullElse(NULL_TIME_UNIT, TimeUnit.SECONDS) + "'");
}
</pre>
<pre style="font-size: 10pt; overflow: auto;">
Feb 28, 2021 2:54:45 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
INFO: Demonstration 'Null-safe String Representation with Objects.requireNonNullElse(Object, Object)' completed without exception!
Feb 28, 2021 2:54:45 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
INFO: Demonstration 'Null-safe TimeUnit access with Objects.requireNonNullElse(Object, Object)' completed without exception!
</pre>
<p>Another <code>Objects</code> method with slightly different name (<a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Objects.html#requireNonNull%28T,java.util.function.Supplier%29" target="_blank">requireNonNullElseGet(T, Supplier<? extends T>)</a>) allows the default that will be used in place of <code>null</code> to be specified using a <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/function/Supplier.html" target="_blank">Supplier</a>. The advantage of this approach is that the operation used to compute that default value will only be executed if the object is <code>null</code> and the cost of executing that <code>Supplier</code> is NOT incurred if the specified object is <code>null</code> (<a href="https://marxsoftware.blogspot.com/2018/05/deferred-execution-java-supplier.html" target="_blank">Supplier deferred execution</a>).</p>
<p><a name="compare-enums"><b>Comparing enums Safely</b></a></p>
<p>Although <a href="https://docs.oracle.com/javase/specs/jls/se15/html/jls-8.html#jls-8.9" target="_blank">Java enums</a> can be compared for equality using <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Enum.html#equals%28java.lang.Object%29" target="_blank">Enum.equals(Object)</a>, <a href="https://marxsoftware.blogspot.com/2011/07/use-to-compare-java-enums.html" target="_blank">I prefer to use the operators</a> <code>==</code> and <code>!=</code> for comparing enums because the latter is <code>null</code>-safe (and arguably makes for easier reading).</p>
<p>The code listing and associated output that follow demonstrate that comparing enums with <code>==</code> is <code>null</code>-safe but comparing enums with <code>.equals(Object)</code> is NOT <code>null</code>-safe.</p>
<pre name="code" class="java">
/**
* Demonstrates that comparing a potentially {@code null} enum is
* {@code null}-safe when the {@code ==} operator (or {@code !=}
* operator) is used, but that potentially comparing a {@code null}
* enum using {@link Enum#equals(Object)} results in a
* {@link NullPointerException}.
*
* See also https://marxsoftware.blogspot.com/2011/07/use-to-compare-java-enums.html.
*/
public void demonstrateEnumComparisons()
{
executeOperation(
"Using == with enums is null Safe",
() -> NULL_TIME_UNIT == TimeUnit.MINUTES);
executeOperation(
"Using .equals On null Enum is NOT null Safe",
() -> NULL_TIME_UNIT.equals(TimeUnit.MINUTES));
}
</pre>
<pre style="font-size: 10pt; overflow: auto;">
INFO: Demonstration 'Using == with enums is null Safe' completed without exception!
Feb 28, 2021 4:30:17 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
SEVERE: Exception encountered while trying to run operation for demonstration 'Using .equals On null Enum is NOT null Safe': java.lang.NullPointerException: Cannot invoke "java.util.concurrent.TimeUnit.equals(Object)" because "dustin.examples.nullsafe.tactics.NullSafeTactics.NULL_TIME_UNIT" is null
Feb 28, 2021 4:30:17 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
</pre>
<p><b><a name="non-null-left-side">Comparing Objects Safely with Known Non-<code>null</code> Object on LHS of <code>.equals(Object)</code></a></b></p>
<p>When we know that at least one of two objects being compared is definitely NOT <code>null</code>, we can safely compare the two objects (even if the other one <em>may</em> be <code>null</code>), by calling <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Object.html#equals%28java.lang.Object%29" target="_blank">Object.equals(Object)</a> against the known non-<code>null</code> object. There still is an element of risk here if the class which you're calling <code>.equals(Object)</code> against has its <code>Object.equals(Object)</code> method implemented in such a way that passing in a <code>null</code> argument leads to a <code>NullPointerException</code>. However, I've never encountered a JDK class or even custom class that has made that mistake (and it is a mistake in my opinion to have a <code>Object.equals(Object)</code> overridden method not be able to handle a supplied <code>null</code> and simply return <code>false</code> in that case instead of throwing <code>NullPointerException</code>). The tactic of calling <code>.equals(Object)</code> against the known non-<code>null</code> object is demonstrated in the next code listing and associated output.</p>
<pre name="code" class="java">
/**
* Demonstrates that comparisons against known non-{@code null} strings can be
* {@code null}-safe as long as the known non-{@code null} string is on the left
* side of the {@link Object#equals(Object)} method ({@link Object#equals(Object)})
* is called on the known non-{@code null} string rather than on the unknown
* and potential {@code null}.
*/
public void demonstrateLiteralComparisons()
{
executeOperation(
"Using known non-null literal on left side of .equals",
() -> "Inspired by Actual Events".equals(NULL_STRING));
executeOperation(
"Using potential null variable on left side of .equals can result in NullPointerExeption",
() -> NULL_STRING.equals("Inspired by Actual Events"));
}
</pre>
<pre style="font-size: 10pt; overflow: auto;">
Feb 28, 2021 4:46:20 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
INFO: Demonstration 'Using known non-null literal on left side of .equals' completed without exception!
Feb 28, 2021 4:46:20 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
SEVERE: Exception encountered while trying to run operation for demonstration 'Using potential null variable on left side of .equals can result in NullPointerExeption': java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because "dustin.examples.nullsafe.tactics.NullSafeTactics.NULL_STRING" is null
</pre>
<p>Although it was specifically String.equals(Object) demonstrated above, this tactic applies to instances of any class as long as the class's <code>.equals(Object)</code> method can gracefully handle a supplied <code>null</code> (and I cannot recall ever encountering one that didn't handle <code>null</code>).</p>
<p><b><a name="case-insensitive-string-left-side">Case Insensitive Comparison of Strings Safely with Known Non-<code>null</code> String on LHS of <code>.equals(Object)</code></a></b></p>
<p>Placing the known non-<code>null</code> object on the left side of the <code>.equals(Object)</code> call is a general <code>null</code>-safe tactic for any object of any type. For <code>String</code> in particular, there are times when we want a <code>null-safe</code> way to compare two strings without regard to the case of the characters in the strings (case insensitive comparison). The <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/String.html#equalsIgnoreCase%28java.lang.String%29" target="_blank">String.equalsIgnoreCase(String)</a> method works well for this and will be a <code>null</code>-safe operation if we use a known non-<code>null</code> <code>String</code> on the left side of that method (method called against the known non-<code>null</code> <code>String</code>).</p>
<p>The code listing and associated output that follow demonstrate <code>null</code>-safe use of <code>String.equalsIgnoreCase(String)</code>.</p>
<pre name="code" class="java">
/**
* Demonstrates that case-insensitive comparisons against known non-{@code null}
* strings can be {@code null}-safe as long as the known non-{@code null} string
* is on the left side of the {@link Object#equals(Object)} method
* ({@link Object#equals(Object)}) is called on the known non-{@code null} String
* rather than on the unknown potential {@code null}).
*/
public void demonstrateLiteralStringEqualsIgnoreCase()
{
executeOperation(
"String.equalsIgnoreCase(String) is null-safe with literal string on left side of method",
() -> "Inspired by Actual Events".equalsIgnoreCase(NULL_STRING));
executeOperation(
"Using potential null variable of left side of .equalsIgnoreCase can result in NPE",
() -> NULL_STRING.equalsIgnoreCase("Inspired by Actual Events"));
}
</pre>
<pre style="font-size: 10pt; overflow: auto;">
Feb 28, 2021 7:03:42 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
INFO: Demonstration 'String.equalsIgnoreCase(String) is null-safe with literal string on left side of method' completed without exception!
Feb 28, 2021 7:03:42 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
SEVERE: Exception encountered while trying to run operation for demonstration 'Using potential null variable of left side of .equalsIgnoreCase can result in NPE': java.lang.NullPointerException: Cannot invoke "String.equalsIgnoreCase(String)" because "dustin.examples.nullsafe.tactics.NullSafeTactics.NULL_STRING" is null
</pre>
<p>These last two demonstrations used literal strings as the "known non-<code>null</code>" strings against which methods were called, but other strings and objects could also be used. Constants and known previously initialized fields and variables are all candidates for the objects against which the comparison methods can be called safely as long as it's known that those fields and variables can never be changed to <code>null</code>. For fields, this condition is only guaranteed if that field is always initialized to a non-<code>null</code> value with the instance and is immutable. For variables, this condition is only guaranteed if that variable is initialized to an unknown value and is <code>final</code>. There are many "in between" cases where it is <em>most likely</em> that certain objects are not <code>null</code>, but guarantees cannot be made. In those cases, it is less risky to explicitly check each object being compared for <code>null</code> before comparing them with <code>.equals(Object)</code> or to use the <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Objects.html#equals%28java.lang.Object,java.lang.Object%29" target="_blank">Objects.equals(Object, Object)</a> method, which is covered next.</p>
<p><b><a name="objects-equals">Safely Comparing Objects When Neither is Known to be Non-<code>null</code></a></b></p>
<p>The <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Objects.html#equals%28java.lang.Object,java.lang.Object%29" target="_blank">Objects.equals(Object, Object)</a> method is a highly convenient way to compare two objects for equality when we don't know whether either or both might be <code>null</code>. This convenience method's documentation explains its behavior and it's probably what most of u would do if writing this code ourselves, "Returns <code>true</code> if the arguments are equal to each other and <code>false</code> otherwise. Consequently, if both arguments are <code>null</code>, <code>true</code> is returned. Otherwise, if the first argument is not <code>null</code>, equality is determined by calling the <code>equals</code> method of the first argument with the second argument of this method. Otherwise, <code>false</code> is returned."</p>
<p>This is demonstrated in the next code listing and associated output.</p>
<pre name="code" class="java">
/**
* Demonstrates that comparisons of even potential {@code null}s is safe
* when {@link Objects#equals(Object, Object)} is used.
*/
public void demonstrateObjectsEquals()
{
executeOperation(
"Using Objects.equals(Object, Object) is null-safe",
() -> Objects.equals(NULL_OBJECT, LocalDateTime.now()));
}
</pre>
<pre style="font-size: 10pt; overflow: auto;">
Feb 28, 2021 5:11:19 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
INFO: Demonstration 'Using Objects.equals(Object, Object) is null-safe' completed without exception!
</pre>
<p><a href="https://marxsoftware.blogspot.com/2011/06/java-7-objects-powered-compact-equals.html" target="_blank">I like to use</a> the <code>Objects.equals(Object, Object)</code> to quickly build my own class's <code>.equals(Objects)</code> methods in a <code>null</code>-safe manner.</p>
<p>The method <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Objects.html#deepEquals%28java.lang.Object,java.lang.Object%29" target="_blank">Objects.deepEquals(Object, Object)</a> is not demonstrated here, but it's worth pointing out its existence. The method's documentation states, "Returns <code>true</code> if the arguments are deeply equal to each other and <code>false</code> otherwise. Two <code>null</code> values are deeply equal. If both arguments are arrays, the algorithm in <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Arrays.html#deepEquals%28java.lang.Object%5B%5D,java.lang.Object%5B%5D%29" target="_blank">Arrays.deepEquals</a> is used to determine equality. Otherwise, equality is determined by using the <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/Object.html#equals%28java.lang.Object%29" target="_blank">equals</a> method of the first argument."</p>
<p><b><a name="null-safe-hash">Null-safe Hashing</a></b></p>
<p>The methods <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Objects.html#hashCode%28java.lang.Object%29" target="_blank">Objects.hashCode(Object)</a> (single object) and <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Objects.html#hash%28java.lang.Object...%29" target="_blank">Objects.hash(Object...)</a> (sequences of objects) can be used to safely generate hash codes for potentially <code>null</code> references. This is demonstrated in the following code listing and associated output.</p>
<pre name="code" class="java">
/**
* Demonstrates that {@link Objects#hashCode(Object)} is {@code null}-safe.
*/
public void demonstrateObjectsHashCode()
{
executeOperation(
"Using Objects.hashCode(Object) is null-safe",
() -> Objects.hashCode(NULL_OBJECT));
}
/**
* Demonstrates that {@link Objects#hash(Object...)} is {@code null}-safe.
*/
public void demonstrateObjectsHash()
{
executeOperation(
"Using Objects.hash(Object...) is null-safe",
() -> Objects.hash(NULL_OBJECT, NULL_STRING, NULL_TIME_UNIT));
}
</pre>
<pre style="font-size: 10pt; overflow: auto;">
Feb 28, 2021 5:11:19 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
INFO: Demonstration 'Using Objects.hashCode(Object) is null-safe' completed without exception!
Feb 28, 2021 5:11:19 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
INFO: Demonstration 'Using Objects.hash(Object...) is null-safe' completed without exception!
</pre>
<p>These methods can be convenient for generating one's own <code>null</code>-safe <code>hashCode()</code> methods on custom classes.</p>
<p>It's also important to note that there is a warning in the documentation that the hash code generated by <code>Objects.hash(Object...)</code> for a single supplied <code>Object</code> is not likely to be the same value as a hash code generated for that same <code>Object</code> when calling the <code>Object</code>'s own <code>hashCode()</code> method or when calling <code>Objects.hashCode(Object)</code> on that <code>Object</code>.</p>
<p style="font-size: 125%;"><b><a name="elegant-necessary">Elegantly Handling Useful <code>NullPointerException</code>s</a></b></p>
<p>The tactics described and demonstrated so far were primarily aimed at avoiding <code>NullPointerException</code> in situations where we fully anticipated a reference being <code>null</code> but that presence of a <code>null</code> is in no way exceptional and so we don't want any exception (including <code>NullPointerException</code>) to be thrown. The remainder of the descriptions and examples in this post will focus instead of situations where we want to handle a truly unexpected (and therefore exceptional) <code>null</code> as elegantly as possible. In many of these cases, we do NOT want to preclude the <code>NullPointerException</code> from being thrown because its occurrence will communicate to us some unexpected condition (often bad data or faulty upstream code logic) that we need to address.</p>
<p>The improved <code>NullPointerException</code> messages have made unexpected <code>NullPointerException</code>s far more meaningful. However, we can often take a few additional tactics to further improve the usefulness of the <code>NullPointerException</code> that is thrown when we run into an unanticipated <code>null</code>. These tactics include adding our own custom context details to the exception and throwing the exception early so that a bunch of logic is not performed needlessly that may also need to be reverted.</p>
<p><b><a name="require-non-null">Controlling When and What Related to Unexpected <code>null</code></a></b></p>
<p>I like to use <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Objects.html#requireNonNull%28T,java.lang.String%29" target="_blank">Objects.requireNonNull(T, String)</a> at the beginning of my <code>public</code> methods that accept arguments which will lead to a <code>NullPointerException</code> if a passed-in argument is <code>null</code>. While a <code>NullPointerException</code> is thrown in either case (either implicitly when an attempt to deference the <code>null</code> or when <code>Objects.requireNonNull(T, String)</code> is called), I like the ability to be able to specify a string with details and context about what's happing when the <code>null</code> is unexpectedly encountered.</p>
<p>The <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Objects.html#requireNonNull%28T%29" target="_blank">Objects.requireNonNull(T)</a> method does not allow one to specify a string with additional context, but it is still a useful guard method. Both of these methods allow the developer to take control of when a <code>NullPointerException</code> will be thrown for the unexpected <code>null</code> and this control allows the developer to preclude unnecessary logic from being performed. We'd rather not waste time/cycles on something that is going to lead to that exception anyway and we can often choose places in the code where it's cleaner to check for <code>null</code> and throw the exception to avoid having to "undo" pr "revert" logic that has been performed.</p>
<p>The following code listing and associated output demonstrate both of these methods in action.</p>
<pre name="code" class="java">
/**
* Demonstrates using {@link Objects#requireNonNull(Object)} and
* {@link Objects#requireNonNull(Object, String)} to take control of
* when an {@link NullPointerException} is thrown. The method accepting
* a {@link String} also allows control of the context that is provided
* in the exception message.
*
* It is not demonstrated here, but a similar method is
* {@link Objects#requireNonNull(Object, Supplier)} that allows a
* {@link Supplier} to be used to provide the message for when an
* unexpected {@code null} is encountered.
*/
public void demonstrateObjectsRequiresNonNullMethods()
{
executeOperation(
"Using Objects.requireNonNull(T)",
() -> Objects.requireNonNull(NULL_OBJECT));
executeOperation(
"Using Objects.requireNonNull(T, String)",
() -> Objects.requireNonNull(NULL_OBJECT, "Cannot perform logic on supplied null object."));
}
</pre>
<pre style="font-size: 10pt; overflow: auto;">
Feb 28, 2021 5:59:42 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
SEVERE: Exception encountered while trying to run operation for demonstration 'Using Objects.requireNonNull(T)': java.lang.NullPointerException
Feb 28, 2021 5:59:42 PM dustin.examples.nullsafe.tactics.NullSafeTactics executeOperation
SEVERE: Exception encountered while trying to run operation for demonstration 'Using Objects.requireNonNull(T, String)': java.lang.NullPointerException: Cannot perform logic on supplied null object.
</pre>
<p>The output shows us that the method that accepted a <code>String</code> was able to provide that additional context in its message, which can be very useful when figuring out why the unexpected <code>null</code> occurred.</p>
<p>I don't demonstrate it here, but it's worth noting that another overloaded version of this method (Objects.requireNonNull(T, Supplier<String>)) allows a developer to use a <code>Supplier</code> to supply a custom <code>NullPointerException</code> for complete control over the exception that is thrown. The use of the <code>Supplier</code> and its <a href="https://marxsoftware.blogspot.com/2018/05/deferred-execution-java-supplier.html" target="_blank">deferred execution</a> means that this exception generation will only be performed when the object is <code>null</code>. One might choose to implement this <code>Supplier</code> as a relatively expensive operation checking various data sources and/or instance values and would not need to worry about incurring that cost unless the unexpected <code>null</code> was encountered.</p>
<p style="font-size: 125%;"><b><a name="other">Other Null-Handling Tactics</a></b></p>
<p>There are other tactics that can be used to either avoid unnecessary <code>NullPointerException</code>s or to make <code>NullPointerException</code>s due to unexpected <code>null</code> more useful. These include explicit checking for <code>null</code> in conditionals and use of <a href="https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Optional.html" target="_blank">Optional</a>.</p>
<p style="font-size: 125%;"><b><a name="conclusion">Conclusion</a></b></p>
<p>This post has discussed and demonstrated tactics for using standard JDK APIs to appropriately avoid unnecessary <code>NullPointerException</code>s and to more effectively use <code>NullPointerException</code>s to indicate unexpected <code>null</code>s. There are several simple tactics to ensure that expected <code>null</code>s do not lead to <code>NullPointerException</code>. There are also tactics available to control when a <code>NullPointerException</code> is thrown and what details are provided in it when an unexpected <code>null</code> is encountered.</p>
<div class="blogger-post-footer"><p>Original posting available at <a href="http://marxsoftware.blogspot.com/">http://marxsoftware.blogspot.com/</a> (Inspired by Actual Events)</p></div>@DustinMarxhttp://www.blogger.com/profile/10790950138196529391noreply@blogger.com1