Monday, February 5, 2018

JDK 9: NotNullOrElse Methods Added to Objects Class

JDK 9 added some new methods to the Objects class including two static methods highlighted in this post: requireNonNullElse(T,T) and requireNonNullElseGet​(T obj,Supplier<? extends T> supplier). Both methods make it easier to verify that a given object is not null and to provide an alternative if the provided variable turns out to be null. As such, these methods and the similar methods introduced to Objects in earlier JDK versions [requireNonNull​(T), requireNonNull​(T,String), and requireNonNull​(T,Supplier<String>)] are most likely to be used to implement guard clauses in methods.

The three methods mentioned in the last paragraph that were added to Objects prior to JDK 9 did not allow a "default" value to be used when the object being tested was determined to be null. Instead, each of these three methods throws a NullPointerException when the variable passed to them is null. The two methods added to Objects in JDK 9 do allow a default to be specified that can be returned by the method rather than the method throwing a NullPointerException.

Objects.requireNonNullElse​(T,T) is the most straightforward approach of the two new added methods for specifying a default object to be returned when the provided variable under test is null. An example of applying this method is shown in the next code listing.

Example of Objects.requireNonNullElse​(T,T)

/**
 * Provide instance of {@code Instant} that corresponds to
 * the provided instance of {@code Date}.
 *
 * @param inputDate Instance of {@code Date} for which
 *    corresponding instance of {@code Instant} is desired;
 *    if this is {@code null}, an {@code Instant} representing
 *    "now" will be returned.
 * @return Instance of {@code Instant} extracted from provided
 *    {@Date} that will instead represent "now" if provided
 *    {@code Date} is {@code null}.
 */
public Instant convertDateToInstantWithNowDefault(final Date inputDate)
{
   final Date dateToConvert
      = Objects.requireNonNullElse(inputDate, new Date());
   return dateToConvert.toInstant();
}

In the above example, if the provided variable of type Date is null, a provided default of "now" (based on calling the Date constructor that doesn't accept arguments) is returned instead.

JDK 9 also added the method Objects.requireNonNullElseGet​(T,Supplier<? extends T>) for a similar purpose. This method differs from the previously discussed method in that it accepts a Supplier for providing the default value rather than accepting another object of the same type to serve as the default.

In the highly recommended book Modern Java Recipes, Ken Kousen writes, "One of the primary use cases for Suppliers is to support the concept of deferred execution." After discussing how Supplier is used in the JDK, he adds, "This process of deferred execution can be used in your own code, to ensure that a value is retrieved from the Supplier only when appropriate." My next example demonstrates this.

A highly contrived code listing is shown next and demonstrates use of this method accepting a Supplier.

Example of Objects.requireNonNullElseGet​(T,Supplier<? extends T>)

/**
 * Provide instance of {@code Instant} that corresponds to
 * the provided instance of {@code Date}.
 *
 * @param inputDate Instance of {@code Date} for which
 *    corresponding instance of {@code Instant} is desired;
 *    if this is {@code null}, an {@code Instant} based on
 *    a complicated date calculation will be returned.
 * @return Instance of {@code Instant} extracted from provided
 *    {@Date} that will instead represent a calculated date if
 *    provided {@code Date} is {@code null}.
 */
public Instant convertDateToInstantWithCalculatedDefault(final Date inputDate)
{
   final Date dateToConvert
      = Objects.requireNonNullElseGet(inputDate, () -> calculateDate());
   return dateToConvert.toInstant();
}

The version of the method accepting a Supplier may be advantageous when the code for determining the default is expected to be long-running. In such cases, that long-running method is only executed if the first passed-in argument is null. When the first passed-in argument is not null, the long-running method is not invoked. [By the way, I don't show the implementation of calculateDate() here because it's ridiculously contrived, but suffice it to say that it intentionally takes a very long time to execute.]

The two methods covered in this post make it easy to detect if a particular variable is null and to provide a suitable replacement in its stead when it is null. These are likely to be most often used to implement "guard clauses," but their ability to return a default value could lead to additional use cases as well.

Saturday, February 3, 2018

An Early Look at Features Targeted for Java 11

With JDK 10 about to enter its release candidate phase, it's interesting to start looking at what will come after that via JDK 11. As of this writing, four JEPs (JDK Enhancement Proposals) have been officially targeted for JDK 11 (with more likely to come). This post summarizes some details about each of the four JEPs currently targeted for JDK 11.

JEP 309: Dynamic Class-File Constants

JEP 309 ("Dynamic Class-File Constants") "seek[s] to reduce the cost and disruption of creating new forms of materializable class-file constants, which in turn offers language designers and compiler implementors broader options for expressivity and performance." JDK bug JDK-8189199 ("Minimal ConstantDynamic support") "implement[s] JEP 309 by properly parsing and resolving new CONSTANT_Dynamic constants in JVM class files used by Hotspot" and was resolved four days ago. JEP 309 was officially targeted for JDK 11 on 14 December 2017.

JEP 318: Epsilon: An Arbitrarily Low-Overhead Garbage Collector

The currently stated goal ofJEP 318 ("Epsilon: An Arbitrarily Low-Overhead Garbage Collector") is to "provide a completely passive GC implementation with a bounded allocation limit and the lowest latency overhead possible, at the expense of memory footprint and memory throughput." The JEP's summary currently states, "Develop a GC that handles memory allocation but does not implement any actual memory reclamation mechanism. Once the available Java heap is exhausted, the JVM will shut down." JEP 318 is associated with issue JDK-8174901 ("JEP 318: Epsilon: An Arbitrarily Low-Overhead Garbage Collector") and was officially targeted for JDK 11 on 18 January 2018. Additional details regarding JEP 318 can be found in online resources such as The Last Frontier in Java Performance: Remove the Garbage Collector and Java garbage collector proposal aimed at performance testing.

JEP 320: Remove the Java EE and CORBA Modules

JEP 320 ("Remove the Java EE and CORBA Modules") has a current "Summary" stating, "Remove the Java EE and CORBA modules from the Java SE Platform and the JDK. These modules were deprecated in Java SE 9 with the declared intent to remove them in a future release." This JEP is not terribly surprising given that CORBA and Java EE modules did not have default visibility in Java SE when JDK 9 introduced modularity. The "Motivation" section of this JEP provides insightful historical background on why Java EE and CORBA modules were included in Java SE in the first place. Among many other interesting tidbits in this "Motivation" section, these two conclusions stand out to me:

  • "Since standalone versions of the Java EE technologies are readily available from third-party sites, such as Maven Central, there is no need for the Java SE Platform or the JDK to include them."
  • "Since the costs of maintaining CORBA support outweigh the benefits, there is no case for the Java SE Platform or the JDK to include it."

JEP 320 lists several modules and tools that it will remove. The to-be-removed modules include java.xml.ws, java.xml.ws.annotation, jdk.xml.ws, java.xml.bind, jdk.xml.bind. The to-be-removed tools include wsgen, wsimport, schemagen, xjc, and servertool.

The JEP 320 "Risks and Assumptions" section illustrates the impact of these removals. It states that developers using --add-modules java.xml.bind currently to include JAXB classes in their Java 9 applications will need to change this for JDK 11. Specifically, the JEP text states, "This proposal assumes that developers who wish to compile or run applications on the latest JDK can find and deploy alternate versions of the Java EE technologies." Fortunately, the text in JEP 320 does a nice job of providing details on current alternate implementations of many of the libraries and tools that will be removed with JDK 11 and JEP 320.

JEP 320 also mentions that most modules it will be removing are "upgradeable," meaning that "developers on JDK 9 who use --add-modules java.xml.bind, etc. have the choice of either relying on the Java EE modules in the JDK runtime image, or overriding them by deploying API JAR files on the upgrade module path." The JEP further explains why this is significant in terms of making it easier to move to JDK 11 when the modules are removed from the JDK runtime image.

JEP 320 is associated with issue JDK-8189188 ("JEP 320: Remove the Java EE and CORBA Modules") and was officially targeted for JDK 11 on 26 January 2018.

JEP 323: Local-Variable Syntax for Lambda Parameters

JEP 323 ("Local-Variable Syntax for Lambda Parameters") is intended to "allow var to be used when declaring the formal parameters of implicitly typed lambda expressions."

JEP 323 is associated with issue JDK-8193259 ("JEP 323: Local-Variable Syntax for Lambda Parameters") and was officially targeted for JDK 11 yesterday (2 February 2018).

Conclusion

I mostly like to look forward to what's coming soon to a JDK near me because I find it interesting to think about. However, there are also practical advantages in some cases to knowing what's coming. For example, JEP 320 provides details regarding alternatives to the modules and tools that will be removed in JDK 11. Developers can start moving to those alternatives now or before migrating to JDK 11 to make that future transition easier.

Dreamix's Java Daily: Aggregation of Fresh Java Online Content

Roughly 18 months ago, I listed three blogs that regularly (daily or weekly) posted links to (and sometimes summaries of) new Java-related blog posts and articles. These blogs were listed under the "Other Resources" section at the bottom of my post "Recent Java News - Early June 2016". Two of those three featured blogs would stop posting those daily/weekly posts with links and summaries by the end of that same year (2016). In this post, I introduce a blog that has come to my attention since then and that I frequently reference when I wish to quickly determine what are the most interesting things going on in the Java online community.

One of the blogs that I featured in my post "Recent Java News - Early June 2016" was Robert Diana's "Geek Reading" series. That series ended approximately one month after my post, but had posted 1150 messages with the "Geek Reading" tag by that time. The reasons for the discontinuation of that series are articulated in the post "Geek Reading July 17, 2016 #1150".

Thorben Janssen's Java Weekly was on my original list, but Janssen concluded (at least temporarily) that series in late 2016 for reasons explained in the post "The end of Java Weekly ... for now." However, Janssen continues to help identify relevant and interesting online resources related to Java via tweets (his Twitter handle is @thjanssen123). It is also important to note that Janssen continues to post original content on his blog.

Of the three blogs that I specifically cited in June 2016 for their links and summaries of fresh Java online content, only the Baeldung Java Web Weekly posts have continued and I still find many good sources of Java-related news from these posts.

The Dreamix blog posts a series called "Java Daily" that provides links to a small number of interesting Java-related blog posts and articles each "working day." These links tend to be to online resources published since the last "Java Daily" blog post. These posts are simple and are typically composed of fewer than ten references with titles and links to the online content. There is typically little or no description beyond what the referenced work's title conveys. I find that the simplicity of these posts and small number of referenced resources allow me to very quickly identify new Java-related posts of interest.

Stoyan Mitov recently posted "Lessons Learned from Publishing the Java Daily during the Entire 2017," in which he writes about "lessons learned from publishing the Java Daily (almost) every working day throughout 2017." He calls this effort "an eye opening experience in the Java world" and outlines eleven "lessons learned from publishing more than 250 Java Dailies in 2017."

Mitov's Java Daily lessons learned post includes a lengthy list of "people one should follow on twitter to stay up to date" with links to the Twitter handle for each of these people. Mitov also references some of my favorite social media sites including DZone, Java Code Geeks, and Baeldung's Best Java Blogs. The post offers approaches to finding new Java sources and this reminds one of the effort that is involved in creating a daily post such as "Java Daily."

In "Lessons Learned from Publishing the Java Daily during the Entire 2017," Mitov makes an observation that I think developers may not fully appreciate until they write a blog of their own: "It's hard to keep up and support a good Java blog." I have seen many of promising blogs that I enjoy come to an end, some of them after a relatively small number of posts. An example of this is the aforementioned Geek Reading. Mitov also observes, "There aren’t so many news on Java on a daily basis. There are many blogs in the form of tutorials – mainly on the basics."

One of the advantages of working with a popular programming language such as Java is access to the thinking of the large community using that language. There is a wealth of online information on Java, but the downside is that it can be difficult to identify the freshest and most interesting new Java-related online resources. Software development social media sites such as DZone and Java Code Geeks help tremendously in this regard, but I have found that these simple recurring blog posts such as those provided by Baeldung's Java Web Weekly, and now by Dreamix's Java Daily, sometimes provide a different perspective on what's interesting that complements those social media sites well.

Thursday, February 1, 2018

JDK 10 Release Candidate Phase

Mark Reinhold's mailing list message "JDK 10 Release Candidate Phase: Process proposal" was posted today and opens with the sentence, "Per the JDK 10 schedule, we'll enter the Release Candidate Phase next week, on Thursday, 8 February." Reinhold proposes that the JDK 10 Release Candidate Phase be enacted in the same manner as the JDK 9 Release Candidate Phase and he provides a link to the (proposed) "JDK 10 Release-Candidate Phase" page. That page outlines the proposed processes associated with the JDK 10 Release Candidate Phase with specific focus on the level of bug fixes targeted for JDK 10. The bugs are categorized as P1 through P5 and once the JDK 10 Release Candidate Phase is entered, "all P2-P5 bugs must be left to future releases" and the focus will be on fixing "all P1 bugs that are new in JDK 10 and critical to the success of the release."

At the time of this writing, the following twelve features are targeted for JDK 10 as we're about to enter the Release Candidate Phase:

Additional References

Tuesday, January 30, 2018

Transferring InputStream to OutputStream in JDK 9

One of the minor additions to JDK 9 that can make a sometimes routine task in Java even easier is the addition of the method InputStream.transferTo(OutputStream). This method, as its name suggests, allows for the easy transfer (copy) of bytes from the input stream represented by the object the method is called upon to the output stream provided to that method. Or, as the method's Javadoc comment states, InputStream.transferTo(OutputStream) "reads all bytes from this input stream and writes the bytes to the given output stream in the order that they are read."

There is more to the Javadoc comment on the InputStream.transferTo(OutputStream) method including these statements:

  • "This method does not close either stream."
  • " It is strongly recommended that both streams be promptly closed if an I/O error occurs."

The easiest way to deal with the two concerns shown above that are expressed in the Javadoc comment for the InputStream.transferTo(OutputStream) method is to instantiate both the source InputStream and the target OutputStream in a try-with-resources statement. An example of this is shown in the next code listing.

StreamsTransfer.java: Using InputStream.transferTo(OutputStream)

package dustin.examples.iostreams;

import static java.lang.System.out;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * Demonstrate InputStream.transferTo(OutputStream) added in JDK 9.
 */
public class StreamsTransfer
{
   /**
    * Demonstrate use of InputStream.transferTo(OutputStream) using
    * FileInputStream and FileOutputStream implementations of
    * InputStream and OutputStream respectively.
    *
    * @param arguments Command-line arguments: one expected,
    *    which is the name of the input file.
    */
   public static void main(final String[] arguments)
   {
      if (arguments.length < 1)
      {
         out.println("USAGE StreamsTransfer <fileName>");
         System.exit(-1);
      }
      final String fileName = arguments[0];
      try (final InputStream is = new FileInputStream(fileName);
           final OutputStream os = new FileOutputStream(fileName + ".copy"))
      {
         is.transferTo(os);
      }
      catch (IOException exception)
      {
         out.println("Exception encountered: " + exception);
      }
   }
}

The try-with-resources statement in the above code listing opens the two resources (instances of InputStream and OutputStream) and so ensures that they are always closed. The implementation of InputStream used in this example is FileInputStream and the implementation of OutputStream used in this example is FileOutputStream.

Although the file copying implemented in the above example could be more easily accomplished in Java with a different mechanism (such as using one of the overloaded Files.copy methods), the approach shown in the code listing above is only intended for easy illustration and can be generalized to any implementations of InputStream and OutputStream. For another example, Josh Bloch discusses use of InputStream.transferTo(OutputStream) in Item 59 of Effective Java (Third Edition) and his illustration uses URL.openStream() as the InputStream and System.out as the OutputStream.

When the above example is executed, it will copy the provided file to another file with the same name with ".copy" added to the end of the new file's name. The two I/O streams are closed even if an exception occurs during processing of either one.

The addition of InputStream.transferTo(OutputStream) seems to be generally welcomed among the Java development community. Ali Dehghani talks about this method in the post "Least significant bits of Java 9." This method is also included in the post "5 things made easier in Java 9" (which also points out that effectively final variables can now be used in try-with-resources rather than explicitly making them final like I did in my example). The Reddit /r/java subreddit includes an interesting discussion titled "New method in JDK 9: InputStream.transferTo(OutputStream)."

Not everyone is fan of the adding of InputStream.transferTo(OutputStream) in JDK 9. In the post "Java 9: The Good, The Bad, and Private Interface Methods", Yegor Bugayenko describes InputStream as an "already over bloated class" and writes that the addition of InputStream.transferTo(OutputStream) is "one of the most typical mistakes young OOP programmers are making: they make their interfaces big ... just because they need more functionality." He also points that IOUtils.copy(InputStream, OutputStream) was already available via Apache Commons.

The addition of the InputStream.transferTo(OutputStream) method with JDK 9 is a small but sometimes very handy addition to the standard JDK that is especially easy to use in conjunction with the try-with-resources statement.

Monday, January 29, 2018

Considerations When Returning Java 8's Optional from a Method

The Optional class introduced with Java 8 has been one of the most controversial features introduced by that version of the language. Although I like more things about this new Java class than I dislike, there are a few things to consider when employing it as a return type in Java methods. I discuss some of them in this post, but don't discuss the controversy about whether Optional should be limited to use as a return type. I also assume that Optional is only used as a return type when it's expected that there are cases where that method should have no value to return. Finally, these observations apply to other types and to direct use of null in Java as well, but Optional emphasizes and concretely illustrates these observations.

Single Versus Multiple Returns

There has been a debate ("religious war") in the general software development community and in the Java development community specifically for some time about whether methods should be written to only return once (not counting throwing exceptions in this discussion). On one side, Yegor Bugayenko argues that "many return statements are a bad idea in OOP", Tom Dalling argues that "having one exit point (return) from a function is a good thing", and many have argued that multiple return statements often indicate need of that method to be refactored. On the other side, Bruce Eckel argues that multiple return statements can make the code "clearer", Taylor Gautier argues that the "maxim" "A method should have one and only one exit point" "couldn't be more wrong", Peter Ritchie argues that strict adherence to single-exit can lead to "less readable" code today in "in Object-Oriented languages", and Mark Levison outlines "some reasons I dislike the single exit argument."

In the post "Multiple Return Statements," Nicolai Parlog writes about the history of and considerations to be made related to the idea of a method returning only once. He includes a section "Situations For Multiple Returns Statements" in which he outlines "several kinds of situations in which a method can profit from multiple return statements." My best guess is that many developers feel the way I do, which is that "it depends" when deciding whether a particular method should have only one return statement or should have more than one return statement.

As I've begun using Java 8's Optional more frequently for my methods' return types, I'm finding that the use of Optional as a return type is another consideration to be made when deciding whether to return once or multiple times from a method.

When declaring that a Java method returns an Optional it's important to fully understand that this does not preclude the developer who writes this method from returning null. The returned Optional is a reference type and, like any reference type, can be null. It is paramount that a developer writing a method that returns Optional should NEVER have that method return null [Optional.empty() should generally be returned instead]. I'm going to reiterate this point with two quotations:

  • Highlighted sentence from Item #55 in Effective Java, Third Edition: "Never return a null value from an Optional-returning method."
  • Stuart Marks's #1 rule for using Optional, "Never, ever, use null for an Optional variable or return value."

One of the arguments against multiple return statements in a method is that it makes it more difficult to recognize what is returned in each case (to find all the different possible return scenarios). The use of Optional as a return type is a specific example illustrating this. One would want to make sure that one's method does not return null in some cases and an Optional instance in other cases. The compiler certainly won't care which is returned in each case.

One approach for dealing with this is to only return from a method once and then the developer writing the code and the developer reviewing the code can easily ensure that null is not returned. These developers would need to only look for an Optional.of(T) call, an Optional.ofNullable(T) call, or an Optional.empty() call.

Work with Local Variable of Underlying Data Type in Method

This approach at avoiding the accidental return of null instead of an empty Optional works best when the Optional is instantiated at the point of return. In other words, I have found it better to work with the type wrapped by the Optional throughout the method and then place it in the Optional at the last possible moment. The next code listing provides ridiculously trivial examples of this.

Examples of Declaring Local Variable that is Ultimately Returned as Optional

/**
 * Provides the middle name if it exists.
 *
 * @return Middle name if it exists or empty if it doesn't exist.
 */
public Optional<String> determineMiddleName1()
{
   String middleName;
   // Do whatever logic is necessary
   return Optional.ofNullable(middleName);
}

/**
 * Provides the middle name if it exists.
 *
 * @return Middle name if it exists or empty if it doesn't exist.
 */
public Optional<String> determineMiddleName2()
{
   Optional<String> middleName;
   // Do whatever logic is necessary
   return middleName;
}

In the above code, the determineMiddleName1() method works with the local variable of the underlying type. This is typically easier to set/populate than Optional and the use of Optional.isNullable() at the ends ensures that even null middleName will be returned as an "empty" Optional instead of null.

The determineMiddleName2() method in the above code declares its local variable that will ultimately be returned as an Optional<String> and then returns that reference at the end of the method.

Avoid "Default" Initialization of Local Variable

As method determineMiddleName2() is written above, the compiler will help ensure that the local variable "middleName" is set to something (even if that "something" is null), but had the developer chosen to initialize that "middleName" variable to null to begin with, the compiler would have no issue with it. If the local variable needs to be initialized for some reason, it would be better to initialize it to Optional.empty() instead of null. Had the developer chosen to initialize that variable with Optional.empty(), it's still possible for that second example to "reset" the local variable to null later in the method.

This discussion leads me to three opinionated observations regarding use of Optional as a method return type in Java.

  1. The influence of single return or multiple returns on the possibility of returning null accidentally instead of an "empty" or other non-null Optional reference should be considered when deciding on whether a single return or multiple returns makes most sense.
  2. It will often be easier to ensure return of an Optional reference rather than return of a null by working on the the underlying type throughout the method and only instantiating the returned Optional at the latest moment (typically at its return).
  3. A local variable of type Optional that is ultimately to be returned from a method should NEVER be initially assigned to null even if it is "known" that it will be re-set appropriately. It may be best to not define it at all so that the compiler will ensure it needs to be set in each "branch" of the code flow. At the very least, if it is to be initialized, that local variable of type Optional should be initialized to Optional.empty() instead of to null.

These observations can be combined. For example, when it's determined that a method should have multiple returns (such as to implement guard clauses), one could return appropriate non-null Optional references at the point of each return and not initialize the local variable until needed (after getting through the guards). This is illustrated with the next ridiculously contrived example.

Example of Avoid Return of Null with Multiple Return Statements

public Optional<String> getGuardedData(final String input)
{
   if (input == null)
   {
      return Optional.empty();
   }

   String data;
   // Do whatever logic is necessary
   return Optional.ofNullable(data);
}

I have found the Optional class, when used properly as a method return type, can make the client's code more readable because of its greater fluency. However, to achieve its maximum value, Optional must be applied with discipline such that clients of the code can expect the returned Optional to never be null. This post has looked at a few considerations that can be made to help ensure that null is never returned from a method that advertises itself as returning Optional. Without trust that the method will never return null, use of Optional as a return type only makes things worse because it forces the client to first check for a non-null Optional before invoking one of the methods on that Optional. That makes the calling code less fluent.

Tuesday, January 23, 2018

Adding Terms to Javadoc Search with Java 9

There is a relatively old web page called "Proposed Javadoc Tags" that appears to have originally been written in conjunction with Javadoc 1.2 that lists "tags that Sun may implement in Javadoc someday." The tags in this list are @category, @example, @tutorial, @index, @exclude, @todo, @internal, @obsolete, and @threadsafety. One of these tags, @index, has moved from "Proposed Tags" to "Standard Tags" with its inclusion in Java 9. The Java 9 Javadoc tool documentation states that the @index tag is used to specify an indexed "search term or a phrase" that can be searched for in Java 9's new Javadoc Search feature.

The ability to add terms for searching in Javadoc generated documentation has been desired for some time as demonstrated by the existence of JDK-4034228 ("stddoclet: Add @index doc-comment tag for generating an index from common words"), JDK-4279638 ("Javadoc comments: Need ability to tag words for inclusion in the API index"), and JDK-4100717 ("Allow user-specified index entries"). JEP 225 ("Javadoc Search") was used to "add a search box to API documentation generated by the standard doclet that can be used to search for program elements and tagged words and phrases within the documentation."

Javadoc in Java 9 and later will automatically include several constructs in the "Search" that can be performed from the generated HTML output. These searchable by default strings are those based on methods' names, members' names, types' names, packages' names, and modules' names. The advantage offered by @index is that phrases or search terms not built into the names of these just-listed constructs can be explicitly to the searched index.

There are several examples of where the ability to add customized text for searching Javadoc generated documentation can be useful. The Javadoc tool documentation references the "domain-specific term ulps" ("units in the last place") and explains that although "ulps is used throughout the java.lang.Math class," it "doesn't appear in any class or method declaration names." Using @index would allow the API designers of the Math class to add "ulps" to the searchable index to help people find the Math class when searching for "ulps." In Effective Java's Third Edition, Josh Bloch references another example of where Javadoc {@index} might be useful. In Item 56, Bloch cites an example using {@index IEEE 754} ("IEEE Standard for Floating-Point Arithmetic").

I recently ran into a case in the JDK where I thought use of {@index} would be appropriate. I posted recently on the Dual-Pivot Quicksort, but realized that one does not find any matches for that term when searching the Javadoc-generated output. It seems like it would be useful to add terms such as "Dual Pivot Quicksort" and "Mergesort" to the Javadoc search index via {@index}.

Unfortunately, having spaces in the text embedded in the {@index } tag seems to result in only the terms before the first space showing up in the rendered HTML (and being the only portions that can be searched). To demonstrate this, the following ridiculously contrived Java code contains three {@index} Javadoc tags representative of the three examples just discussed.

Java Code Using {@index} in Its Documentation

package dustin.examples.javadoc;

/**
 * Used to demonstrate use of JDK 9's Javadoc tool
 * "@index" tag.
 */
public class JavadocIndexDemonstrator
{
   /**
    * This method complies with the {@index IEEE 754} standard.
    */
   public void doEffectiveJava3Example()
   {
   }

   /**
    * Accuracy of the floating-point Math methods is measured in
    * terms of {@index ulps}, "units in the last place."
    */
   public void doMathUlpsExample()
   {
   }

   /**
    * This method uses a version of the {@index Dual-Pivot Quicksort}.
    */
   public void doDualPivotQuicksort()
   {
   }
}

When the Javadoc tool is executed against the above code on my Windows 10 machine in Java 9.0.4, the generated HTML page looks like this:

The "754" is missing in the generated HTML after "IEEE" and the "Quicksort" is missing after "Dual-Pivot" in the methods' documentation. The next code listing shows the generated HTML source code for these pieces with missing text.

HTML Source

<div class="block">This method uses a version of the <a id="Dual-Pivot" class="searchTagResult">Dual-Pivot</a>.</div>
 . . .
<div class="block">This method complies with the <a id="IEEE" class="searchTagResult">IEEE</a> standard.</div>

From the HTML output just shown, it becomes apparent why only the text before the first space appears in the page and is searchable. The "id" attribute associated with the "searchTagResult" class for each searchable entry consists of the searchable string. Because HTML "id" attributes cannot have spaces, only the characters up to the first space can be used for the "id" value.

Because spaces are not allowed in the "id" attributes, one of the following work-arounds would need to be used when dealing with multiple words in a single phrase for which search is desired.

  1. Remove spaces
    • "{@index IEEE 754}" becomes "{@index IEEE754}"
    • "{@index Dual-Pivot Quicksort}" becomes "{@index Dual-PivotQuicksort}"
  2. Replace spaces with allowable character (for example, hyphen)
    • "{@index IEEE 754}" becomes "{@index IEEE-754}"
    • "{@index Dual-Pivot Quicksort}" becomes "{@index Dual-Pivot-Quicksort}"
  3. Use separate {@index} for each word in phrase
    • "{@index IEEE 754}" becomes "{@index IEEE} {@index 754}"
    • "{@index Dual-Pivot Quicksort}" becomes "{@index Dual-Pivot} {@index Quicksort}"
  4. Use {@index} only on most important terms in phrase
    • "{@index Dual-Pivot Quicksort}" becomes "{@index Dual-Pivot} Quicksort"
  5. Represent multiple word phrase with common single word representation
    • This is why "ulps" in the Javadoc tool documentation works well rather than "units in the last place."

The "Motivation" section of JEP 225 ("Javadoc Search") nicely summarizes the benefits of this ability to search for terms in Javadoc:

The API documentation pages generated by the standard doclet can be hard to navigate if you're not already familiar with their layout. An external search engine can be used, but that may lead to an out-dated or irrelevant page. The browser's built-in search function can be used, but that is limited to searching within the current page rather than an entire body of documentation.

Although adding search capability to Javadoc-generated documentation is a minor addition in Java 9, it can be used to make documentation of one's Java code more useful to other developers and users of that code.