Tuesday, February 20, 2018

JDK 10: Accessing Java Application's Process ID from Java

A popular question on StackOverflow.com is, "How can a Java program get its own process ID?" There are several answers associated with that question that include parsing the String returned by ManagementFactory.getRuntimeMXBean().getName() [but that can provide an "arbitrary string"], using ProcessHandle.getPid() [JEP 102], using Java Native Access (JNA), using System Information Gatherer And Reporter (SIGAR), using JavaSysMon, using Java Native Runtime - POSIX, parsing the results of jps (or jcmd) via invocation of Runtime.getRuntime().exec(String), and other approaches. JDK 10 introduces perhaps the easiest approach of all for obtaining a JVM process's PID via a new method on the RuntimeMXBean.

JDK-8189091 ("MBean access to the PID") introduces the RuntimeMXBean method getPid() as a default interface method with JDK 10. That issue states the "Problem" as: "The platform MBean does not provide any API to get the process ID of a running JVM. Some JMX tools rely on the hotspot implementation of RuntimeMXBean::getName which returns < pid >@< hostname >." The issue also provides the "Solution": "Introduced new API java.lang.management.RuntimeMXBean.getPid, so that JMX tools can directly get process ID instead of relying on the implementation detail, RuntimeMXBean#getName().split("@")[0]."

The next code listing is a simple one and it demonstrates use of this new getPid() method on RuntimeMXBean.

Using JDK 10's RuntimeMXBean.getPid()

final RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
final long pid = runtime.getPid();
final Console console = System.console();
out.println("Process ID is '" + pid + "' Press <ENTER> to continue.");

When the code above is contained within an executable main(String[]) function and that function is executed from the command line, the output is as shown in the next screen snapshot (which also includes a separate terminal used to verify the PID is correct via jcmd).

The process ID is provided as a long and no parsing of an "arbitrary string" is necessary. This approach also does not require a third-party library or elaborate code to determine the current Java process's identifier.

This post has provided a brief introduction to what will perhaps be the easiest approach for a Java application (written with JDK 10 or later) to determine its own underlying process ID.

Monday, February 19, 2018

JDK 10's Summary Javadoc Tag

JDK 10 introduces a Javadoc tag {@summary} via issue JDK-8173425 ("Javadoc needs a new tag to specify the summary."). This new tag allows the developer to explicitly specify what portion of the Javadoc comment appears in the "summary" rather than relying on Javadoc's default treatment looking for a period and space to demarcate the end of the summary portion of the comment. JDK-8173425 states, "Currently in javadoc the summary (firstsentence) of an element is deciphered by a dot-space rule, or if required using BreakIterator." It adds that it can be confusing to know what that implicitly selected summary sentence will be.

The easiest way to see {@summary} in action may be through Javadoc examples. The next code listing shows four methods with similar Javadoc comments, two using explicit {@summary} tags and two relying on implicit Javadoc summary construction.

Demonstrating {@summary} in Javadoc Method Comments

package dustin.examples.javadoc;

 * Demonstrate JDK 10 added summary support. Demonstrates
 * this by comparing similar methods' Javadoc comments with
 * and without use of new "@summary" tag.
public class Summary
    * This method's first sentence is normally in the summary.
    * Here are some of its characteristics:
    * <ul>
    * <li>This method does great things.</li>
    * <li>This method does not really do anything.</li>
    * </ul>
   public void implicitSummary1()

    * This method's first sentence is normally in the summary.Here are some of its characteristics:
    * <ul>
    * <li>This method does great things.</li>
    * <li>This method does not really do anything.</li>
    * </ul>
   public void implicitSummary2()

    * {@summary This method's first sentence is normally in the summary.
    * Here are some of its characteristics:
    * <ul>
    * <li>This method does great things.</li>
    * <li>This method does not really do anything.</li>
    * </ul>}
   public void explicitSummary1()

    * {@summary This method's first sentence is normally in the summary.Here are some of its characteristics:
    * <ul>
    * <li>This method does great things.</li>
    * <li>This method does not really do anything.</li>
    * </ul>}
   public void explicitSummary2()

When the Javadoc tool delivered with the first JDK 10 (18.3) Release Candidate (Build 43) is executed against this simple class, the "Method Summary" section of the generated HTML appears as follows in a web browser.

Comparing the HTML output to the commented Java code above it demonstrates how the {@summary} allows for explicit control of what appears in the methods' summaries.

Saturday, February 17, 2018

String#repeat Coming to Java?

JDK-8197594 ("String#repeat") includes the following it its "Description": "A String method for repeating sequences of characters has been long requested with no follow through." Evidence of this interest in a method on the String class for repeating sequences of characters can be found in JDK-8197594's "Issue Links" that include JDK-8055862 ["Provide a String repeat method"] and JDK-6984084 ["(str) n times repetition of character constructor for java.lang.String"]. Both of these linked issues describe motivations for having such a method in the String class. Further evidence includes online questions such as Simple way to repeat a String in java, How to repeat string “n” times in java?, What is the simple way to repeat a string in Java?, and How do you repeat a string n number of times in Java programming?

Guava provides this desired behavior via its Strings.repeat(String, int) method and Apache Commons Lang provides this functionality via its StringUtils.repeat(String, int). It's also likely that this functionality has been implemented hundreds of times or more in individual projects. The availability of a standard java.lang.String.repeat(String, int) method could replace all of these.

The discussion on the core-libs-dev JDK mailing list regarding JDK-8197594 offers up some additional intriguing details regarding this likely addition to a future version of Java.

One interesting point is made in Jim Laskey's message in which he describes potential performance improvements that this method would provide. Specifically, Laskey writes that "performance runs with jmh ... show that these methods are significantly faster than StringBuilder equivalents" and Laskey attributes this to "fewer memory allocations," "fewer char to byte array conversions," and "faster pyramid replication vs O(N) copying." Because this is open source, the currently proposed implementation that brings these performance benefits is provided. For those who are interested, the two aforementioned open source projects have obviously made their source code available [Guava's Strings.repeat(String, int) and Apache Commons Lang's String repeat(String, int)].

Brian Goetz has posted a second reason for adding a method such as String.repeat in the standard API: to turn common functionality implemented via statements into composible expressions. Goetz explains, "My primary motivation for these sorts of methods is to take things that require execution as _statements_ (loops, if-then, etc) and turn them into _expressions_, not primarily because they are more compact, but because they are then _composible_." Goetz has described the advantages of expressions before and this is one of the primary motivations of the draft JEP related to switch expressions in Java.

A new method on java.lang.String to repeat a character sequence a specified number of times won't be as big of a deal as many other new API additions and new language features, but it can provide advantages such as not needing third-party or custom implementations, improved performance, and a standardized expression form of a commonly implemented behavior. As of this writing, JDK-8197594 is not associated with a particular Java version and is instead labeled "tbd_feature".

Friday, February 16, 2018

First JDK 10 (18.3) Release Candidate (Build 43) Demonstrates New Versioning Scheme

Mark Reinhold's post "JDK 10: First Release Candidate" announced "no unresolved P1 bugs in build 43" and named that Build 43 the initial JDK 10 Release Candidate. The Reinhold post also points to the "JDK 10 Early-Access Builds" page which contains links to the release notes; to the Javadoc-based API documentation; to the "early-access, open-source builds" (OpenJDK) for Windows, Linux, macOS, and Alpine Linux; and to the Oracle JDK builds.

The following screen snapshot shows the version information provided by the OpenJDK 10 Build 43 (the text in the screen snapshot is reproduced below the image):

openjdk version "10" 2018-03-20
OpenJDK Runtime Environment 18.3 (build 10+43)
OpenJDK 64-Bit Server VM 18.3 (build 10+43, mixed mode)

The next screen snapshot shown the version information provided by the Oracle JDK 10 Build 43 (the text in the screen snapshot is reproduced below the image):

java version "10" 2018-03-20
Java(TM) SE Runtime Environment 18.3 (build 10+43)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10+43, mixed mode)

As the above screen snapshots show, the -version information for the OpenJDK and OracleJDK currently show both forms. They show the "10" in quotes for JDK 10, but they also show 18.3. This is consistent with the JSR 383 title ["Java SE 10 (18.3) Platform JSR (383)"] and its description.

There has been some confusion regarding the versioning scheme for versions of Java after JDK 9 because of rapid changing developments in plans for Java version names. Some key posts on the developing version naming after JDK 9 are shown below.

  1. Moving Java Forward Faster (6 September 2017)
    • 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."
    • "To make it clear that these are time-based releases, and to make it easy to figure out the release date of any particular release, the version strings of feature releases will be of the form $YEAR.$MONTH." This is where the "18.3" comes from in the above examples (representing March 2018).
    • Related post "Accelerating the JDK release cadence" discusses approaches to be taken with "the ultimate goal" of making "OpenJDK and Oracle JDK builds completely interchangeable."
  2. Version-string schemes for the Java SE Platform and the JDK (19 October 2017)
    • Addresses community concern and responses (such as this one) to original proposal.
    • Outlines criteria to be considered when selecting a versioning scheme.
    • Presents potential alternatives that satisfy the outlined criteria.
    • References Wadler's Law.
  3. Proposal: Newer version-string scheme for the Java SE Platform and the JDK (2 November 2017)
    • Introduces scheme $FEATURE.$INTERIM.$UPDATE.$EMERG
    • $FEATURE is "the feature-release counter, incremented every six months regardless of release content."
    • "This is primarily a time-based scheme, since $FEATURE is incremented every six months regardless of release content and, for each feature release, $UPDATE is incremented every three months."
    • JEP 223-compliant system property java.version.date is added and is the "intended GA date" in "ISO-8601 YYYY-MM-DD format." It is "some date in the future" for early access releases. In the examples above, the expected release General Availability release date is 2018-03-20.
  4. Updating the version number (1 December 2017)
    • States that JSR-383 documents will be updated to reference "10 (18.3)" instead of "18.3".
  5. Why do "Oracle JDK 10 builds" not support AppCDS? (16 February 2018)
    • I include this post because it provides a specific concrete example of how the version name differs for early access builds ("10-ea+42") versus release candidate builds intended for eventual general availability ("10+43").

The screen snapshots shown in this post depict the versions associated with the available initial build of JDK 10 Release Candidate. This initial build provides an early look at the new JDK version naming scheme in action.

Monday, February 12, 2018

APIs To Be Removed from Java 10

In the blog post "JDK 10 Release Candidate Phase", I looked at the twelve new features that are likely to be part of JDK 10. In this post, I look at some of the APIs that appear likely to be removed in JDK 10 and I look at some APIs proposed to be deprecated in JDK 10. The information in this post is based on the current version (2018/1/31 19:49 -0800 [a337d4f5aa79]) of "Java SE 10 (18.3) (JSR 383) Proposed Final Draft Specification - DRAFT" and, because this source document is a draft, this information is subject to change.

The JDK 9 enhanced deprecation feature (JEP 277) allowed several JDK APIs to be annotated with @Deprecated's new optional forRemoval() element to be set to true, which indicates that the annotated API "is earmarked for removal in a future release." The following APIs had this enhanced deprecation applied, were marked for "removal in a future release" in JDK 9, and now JDK 10 appears to be the version in which they'll be removed.

As currently proposed, JDK 10 will add the optional annotation element forRemoval=true to some previously deprecated [@Deprecated] API elements that did not formerly have forRemoval set. These include security-related interfaces, classes, and exceptions that have been replaced by other security-related constructs (many were replaced as far back as JDK 1.2). Several "finalize"-ending methods also have their @Deprecated annotation enhanced to indicate that as of JDK 10 they are "earmarked for removal in a future release." For example, FileInputStream.finalize() was deprecated in JDK 9, but will be marked with forRemoval=true as of JDK 10.

Most of the JDK API constructs to be removed in JDK 10 have been deprecated for a long time (since JDK 1.2 or earlier) and so there has been plenty of time to replace use of these. Most of the JDK API constructs newly denoted in JDK 10 to be removed in a future release have already been deprecated and this change is only to indicate that they now will likely be removed in a future release. The JDK 9-introduced enhanced deprecation mechanism allows the JDK API to have constructs more aggressively removed after having their likely removal advertised in advance via the forRemoval=true element of the @Deprecated annotation. JDK 9 removed several things and it appears likely that JDK 10 will continue the removal of certain previously deprecated API elements.

Saturday, February 10, 2018

Executing Single Java Source Files with One Command

A draft JDK Enhancement Proposal (JEP) was created in late 2017 called "Launch Single-File Source-Code Programs" (its associated JDK issue is JDK-8192920). As its name suggests, this draft JEP aims to "enhance the java launcher to support running a program supplied as a single file of Java source code." In other words, as the JEP describes, if one had a typical self-contained HelloWorld.java source code code file, one could simply run java HelloWorld.java from the command line rather than needing to use javac to compile HelloWorld.java into HelloWorld.class before running it with the java launcher.

JEP owner Jonathan Gibbons summarized this when he introduced the JEP on the compiler-dev mailing list:

This draft JEP contains a proposal to enhance the |java| launcher to support running a program supplied as a single file of Java source code. The program will be compiled and run, without the need to explicit invoke javac, or to package up a jar file.

The primary use cases for such a feature are expected to be for people to run very simple Java applications (the JEP calls them "small utility programs") and people wanting to learn about basic Java features. I have described similar use cases in my blog posts "Learning Java via Simple Tests" and "Compiling and Running Java Without an IDE". The JEP states that in the context of these use cases, "it is pure ceremony to have to compile the program before running it. In addition, a single source file may compile to multiple class files, which adds packaging overhead to the simple goal of 'run this program'. It is desirable to be able to run the program directly from source with the java launcher."

There have been two interesting discussion points on the JDK mailing lists related to this draft JEP. One of the topics discussed is the ability to put a "shebang" on the first line of a Java source code file that is intended to be run in the way this JEP describes (such as used in Groovy and numerous other languages running in Linux/Unix shells). As of this writing, the draft JEP currently addresses this topic under the section heading "Shebang" files and states:

A "shebang" file to invoke the Java launcher using source-file mode will typically begin with something like:

#!/path/to/java --source

To allow for such files in source-file mode, if the file begins with #! the contents of the first line up to but not including the first newline are removed before compiling the rest of the file. ... When the file begins with #!, the newline at the end of the first line is preserved so that the line numbers in any error messages remain unchanged.

The second interesting discussion point associated with this draft JEP is the question if its relationship with the jshell introduced with JDK 9. As Brian Goetz states in his message on the compiler-dev mailing list, it is "a natural (and common) thought" to expect that jshell would be used instead of the enhanced java launcher to run these shell-like single source Java source files. Goetz explains in that message why this isn't as good of an idea as it would first seem because jshell was explicitly designed for a "a good interactive experience" rather than as a "batch runner." The current version of the draft JEP addresses this in the Alternatives section, which states:

We could delegate the task of "one-off runs" to the jshell tool. While this may at first seem obvious, this was an explicit non-goal in the design of jshell. The jshell tool was designed to be an interactive shell, and many design decisions were made in favor of providing a better interactive experience. Burdening it with the additional constraints of being the batch runner would detract from the interactive experience.

Although this is only a draft JEP at this point, I like the idea and think it would be a nice minor feature to have added to a future version of the JDK. This feature would allow basic Java examples to be more easily tested by those new to Java and would not burden the novice Java developer with extra steps that he or she is not accustomed to using with some other (often dynamically typed) programming languages. It would also be convenient for more experienced Java developers. I still find myself writing small Java snippets to learn how something works (and to demonstrate to others how it works) and this draft proposed JDK enhancement would make that a bit easier, especially when the Java source file compiles into multiple .class files. This is one of the features I've enjoyed with Groovy development and it'd be nice to have it for simple Java development.

Monday, February 5, 2018

Java 8: Bastion of Long-term Support

Stephen Colebourne's post "Java 9 has six weeks to live" starts, "Java 9 is obsolete in just six weeks." Colebourne references the Mark Reinhold blog post "Moving Java Forward Faster" and writes, "The new Java release train means that there will be a new release of Java every six months. And when the next release comes out, the previous release is obsolete." Colebourne points out that those still on Java 8 can enjoy this "current LTS (long term support) release until the next LTS release occurs (Java 11)." However, for those who have already moved to Java 9, different choices must be made and Colebourne outlines these choices at a high level. Colebourne outlines several types of dependencies that must also move forward every six months and concludes, "I think it's fair to say that it's a bold choice to use Java 9 or 10."

As a reminder, the aforementioned Reinhold blog post "Moving Java Forward Faster" outlines how the new proposed release train addresses "the tension between developers, who prefer rapid innovation, and enterprises, which prefer stability, and the fact that everyone prefers regular and predictable releases." The following are key points of this new release train approach:

  • "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." (I added the emphasis)
  • Feature Releases (which "contain any type of feature") ship in March and September of each year with the first one being March 2018 (JDK 10 that Colebourne references when he writes, "Java 9 has six weeks to live").
  • Update Releases (which are "strictly limited to fixes of security issues, regressions, and bugs in newer features") occur between the Feature Releases with two Update Releases between each Feature Release and scheduled with quarter periodicity in the months of January, April, July, and October.
  • Long-Term Support Releases are the same as the Feature Release every third year starting in September 2018. Updates for these long-term support releases will be available at least until the next long-term support release and often may be available longer than those three years.
  • Additional details regarding the Java release train can be found at the #javatrain Twitter handle, in the General OpenJDK Discussion distribution list, in the page "Oracle Java SE Support Roadmap," and in the page "Faster and Easier Use and Redistribution of Java SE."
  • It was recently announced that "the public availability of Java SE 8 updates from Oracle has been extended to at least January 2019" and that "Oracle will continue to provide consumers with updates for personal (non-corporate) use of Java SE 8 through at least the end of 2020."

Colebourne is not the only one to warn Java developers to consider the ramifications of moving from Java 8 to Java 9. In the post "Java 9: No Long-Term Support and Twice-Yearly JDK Releases," Carly Yuk writes that "Java 9 will not be entitled to long-term maintenance." Yuk adds that "enterprises that are running applications in products may want to consider waiting for the future long-term release." Paul Krill writes that "Java 9 will not receive long-term support" and Ben Evans has been paraphrased, "Since Oracle has announced that Java 8 will be a long-term support release, supported through 2022, Evans thinks that a lot of applications might stay on Java 8 and not upgrade to Java 9 at all."

There is much to think about when deciding whether to upgrade to Java 9 or not. There is no single "correct" answer as situations, environments, priorities, and uses of Java differ greatly. In general, developers of larger "enterprise" type applications will likely want to only adopt the long-term support releases and developers of smaller applications will likely be willing to adopt feature releases and associated update releases to get access to new features sooner. This ability to choose between "rapid innovation" and supported stable versions is one of the driving motivations for the new release train.