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.

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.