Thursday, September 27, 2018

A Tale of Two Oracle JDKs

There has been concern recently that Java developers will inadvertently use the wrong Oracle-provided JDK implementation now (as of JDK 11) that Oracle provides builds of the open source OpenJDK and also provides commercial JDK builds based largely on the OpenJDK source.

The table below compares and contrasts the two versions of JDK that Oracle provides (but Oracle won't be the only supplier of JDK builds available for free and/or for support charge). Please keep in mind this represents my best personal understanding of the differences and similarities of Oracle's two offerings; please check with an authoritative source before making decisions regarding which Oracle JDK implementation to use (or even whether to use an Oracle implementation).

JDK Builds from Oracle (https://jdk.java.net/)
Characteristic Oracle OpenJDK Builds Oracle JDK (Java SE Downloads)
Oracle's Descriptions "End users and developers looking for free JDK versions: Oracle OpenJDK offers the same features and performance as Oracle JDK under the GPL license." "Oracle Customers and ISVs targeting Oracle LTS releases: Oracle JDK is Oracle's supported Java SE version for customers and for developing, testing, prototyping or demonstrating your Java applications."
Web Address https://jdk.java.net/11/ https://www.oracle.com/technetwork/java/javase/downloads/jdk11-downloads-5066655.html
License GNU General Public License, version 2, with the Classpath Exception Oracle Technology Network License Agreement for Oracle Java SE
Build Platforms (Binaries) Linux / x64 (tar.gz)
macOS / x64 (tar.gz)
Windows / x64 (zip)
Linux / x64 (tar.gz, deb, rpm)
macOS / x64 (tar.gz, dmg)
Windows / x64 (zip, exe)
Solaris SPARC (tar.gz)
Pay for Production Use No Yes
Oracle Support Select bug fixes and security patches until next JDK version's General Availability release Java SE Subscription
(Support for LTS versions for up to 8 years)
Several Other Paid Support Offerings under "Oracle Customers"
java -version Example openjdk version "11" 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)
java version "11" 2018-09-25
Java(TM) SE Runtime Environment 18.9 (build 11+28)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11+28, mixed mode)
Required to Accept License Agreement No Yes
Java Flight Recorder Yes Yes
Java Mission Control Yes Yes
Advanced Management Console No Yes
This table represents my personal understanding only; refer to Oracle documentation and OpenJDK documentation for more authoritative information (see "References" below).

There are other implementations of the JDK that will be available as well, with some being free and some requiring payment. I did not discuss those alternatively provided JDKs in this post in order to keep the comparison cleaner and simpler between the "Oracle OpenJDK builds" and the "Oracle JDK builds".

References

Tuesday, September 25, 2018

JDK 11 General Availability

As scheduled, it was announced today that JDK 11 was released for General Availability. Earlier this week, Iris Clark announced the "JSR 384 (Java SE 11) Final Release" and in that same message referenced the final release version of JSR 384, referenced the "Java SE 11 (18.9) Platform JSR (384)" specification page, and concluded, "The 384 EG is now disbanded."

The "JDK 11 General-Availability Release" page provides "production-ready open-source builds of the Java Development Kit, version 11, an implementation of the Java SE 11 Platform under the GNU General Public License, version 2, with the Classpath Exception." That same JDK 11 GA Release page also points to "commercial builds of JDK 11 from Oracle under a non-open-source license" that are "available for a wider range of platforms" and which "can be found at the Oracle Help Center."

The "JDK 11 GA Release" page also provides links to the detailed JDK 11 Release Notes, to the list of features (JEPs) associated with JDK 11, to the Java SE/JDK Version 11 API Specification (Javadoc), and to the Java SE 11 Tools and Command Reference.

In the message "Java 11 / JDK 11: General Availability", Mark Reinhold writes:

JDK 11, the reference implementation of Java 11 and the first long-term support release produced under the six-month rapid-cadence release model[1][2], is now Generally Available. We've identified no P1 bugs since we promoted build 28 over four weeks ago so that’s the official GA release, ready for production use.

JDK 11 is significant for several reasons, not the least of which is its status as the basis for Oracle's LTS offering and the likelihood of this being the version of Java many shops will move to if they are currently on Java 8. An interesting read along these lines for those who do not intend to purchase commercial support for Oracle JDK implementations is "The future of Java and OpenJDK updates without Oracle support." Other recent posts that are probably worth reading in light of JDK 11's release are "Oracle JDK Releases for Java 11 and Later", "Java Is Still Free", and "Introducing Java SE 11".

Oracle's "Java SE Development Kit 11 Downloads" page highlights (in orange-ish background and with emphasized title "Important changes in Oracle JDK 11 License") the "substantially different" Oracle Technology Network License Agreement that now applies to Oracle Java SE and provides a link to "this software under the GPL License on jdk.java.net/11" (Oracle's OpenJDK builds).

Monday, September 24, 2018

Raw String Literals Support in JDK 12 Early Access Build 12

The biggest news this week in the world of Java is likely going to be the General Availability of JDK 11. However, another exciting development is the release of JDK 12 Early Access Build 12 (20 September 2018). This Early Access Build 12 of JDK 12 is significant because it includes implementations related to JEP 326 ["Raw String Literals (Preview)"] via changesets such as changeset 51713:d424675a9743 (JDK-8206981), changeset 51714:975d3636a2f9 (JDK-8200434), and changeset 51725:ccea318862ae (JDK-8210674).

JEP 326 itself displays multiple examples of how raw string literals might be applied in Java code in common situations (file paths, multi-line, regular expressions, database/SQL, and polyglot). These examples also appear in an arguably more readable format in associated JDK-8196004. These "Raw String Literals" examples can be pasted into Java classes/methods and compiled successfully against JDK 12 Early Access Build 12. For convenience, I've placed slightly adapted versions of these in a single Java class on GitHub.

Note that JEP 326 is a "Preview Feature", so you must compile with the javac options --enable-preview and --release 12 or else you'll encounter the error message, "error: raw string literals are a preview feature and are disabled by default" with a pointer to the backtick used to demarcate the raw string literal. Similarly, the code must be run with java launcher option --enable-preview to run successfully and to avoid the error message, "... UnsupportedClassVersionError: Preview features are not enabled ..."

As far as I can determine, Early Access Build 12 does not include an implementation for JDK-8202442 ["String::unescape"]. Some of the library methods added to the String class related to raw string literals are part of JDK 11 and I discussed some of these in the post "Applying New JDK 11 String Methods".

Wednesday, September 19, 2018

JDK Bug System Time Wasters

Several possibilities of the message's possible contents crossed my mind when I saw the title of Jesper Wilhelmsson's message "Introducing time wasters" on the OpenJDK jdk-dev mailing list. In the second or so between reading that link and having the message appear after clicking on the link, I wondered if the message would be about one of the following topics:

  • People wasting the time of developers working on the JDK
  • People wasting the time of developers sharing ideas and responding to questions on the mailing lists
  • Trivial defect reports or reports of observations that are intentional (not defects)

It turns out that Wilhelmsson's topic was more interesting than those. Wilhelmsson opens the message with these two sentences (I added the emphasis), "As an experiment we are introducing a new label in JBS, timewaster. The label is used to tag bugs that for some reason is wasting engineering time." That message provides additional considerations to be made when deciding whether to label a bug in JDK Bug System (JBS) with the "timewaster" label.

The "Labels" section of the JBS Overview page describes the purpose of JBS labels: "Users can associate one or more labels with an issue. Such labels are often used to manage informal processes and record ad hoc information." Although a given label does not necessarily change the priority of a bug (it communicates importance informally rather than formally), Wilhelmsson points out that the "timewaster" label communicates additional urgency, "A time waster has higher urgency than other bugs."

Jesper Wilhelmsson's post spells out some examples where this "timewasters" label might be used. Here are some bugs from the JBS that may have been or may be appropriate for such a label given the text in the bug.

It will be interesting to see how the "timewaster" experiment works out and how the criteria for determining what is a "timewaster" and what is not develops. I just wish I could label some of the defects I get assigned as time wasters.

Monday, September 17, 2018

Java Subtlety with Arrays of Primitives and Variable Arguments

An interesting question was posed in a comment on the DZone-syndicated version of my recent blog post "Arrays.hashCode() Vs. Objects.hash()". The comment's author set up examples similar to those used in my blog post and showed different results than I saw. I appreciate the comment author taking the time to post this as it brings up a subtle nuance in Java that I think is worth a blog post.

The comment author showed the following valid Java statements:

int[] arr = new int[]{1,2,3,4};
System.out.println(Arrays.hashCode(arr));
System.out.println(Objects.hash(1,2,3,4));
System.out.println(Arrays.hashCode(new Integer[]{new Integer(1),new Integer(2),new Integer(3),new Integer(4)}));
System.out.println(Objects.hash(new Integer(1),new Integer(2),new Integer(3),new Integer(4)));

The author of the comment mentioned that the results from running the code just shown were exactly the same for all four statements. This differed from my examples where the result from calling Arrays.hashCode(int[]) on an array of primitive int values was different than calling Objects.hash(Object...) on that same array of primitive int values.

One response to the original feedback comment accurately pointed out that hash codes generated on different JVMs are not guaranteed to be the same. In fact, the Javadoc comment for the Object.hashCode() method states (I added the emphasis):

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

Having stated all of this, the hash codes calculated for integers will typically be consistent from run to run. It was also interesting that the original commenter's examples' output all had exactly the same values. While I might not expect those values to match my examples' values, it is surprising that all of the examples provided by the commenter had the same answer.

The difference between the examples provided in the feedback comment and my examples comes down to how the commenter's example invoked Objects.hash(Object...) for an array of primitive int values versus how my example invoked Objects.hash(Object...) for an array of primitive int values. In my example, I passed the same local array to all the method calls. The commenter's example passed an explicit array of primitive int values to Arrays.hashCode(int[]), but passed individual int elements to Objects.hash(Object...) instead of passing the array to that latter method. When I add another example to the commenter's set of examples that does pass the array of primitive int values to the Objects.hash(Object...) method, I get a generated hash code that is different than all of the others. That enhanced code is shown next.

final int[] arr = new int[]{1,2,3,4};
out.println("Arrays.hashCode(int[]):              " + Arrays.hashCode(arr));
out.println("Objects.hash(int, int, int, int):    " + Objects.hash(1,2,3,4));
out.println("Objects.hash(int[]):                 " + Objects.hash(arr));
out.println("Objects.hashCode(Object):            " + Objects.hashCode(arr));
out.println("int[].hashCode():                    " + arr.hashCode());
out.println("Arrays.hashCode(Int, Int, Int, Int): " + Arrays.hashCode(new Integer[]{1,2,3,4}));
out.println("Objects.hash(Int, Int, Int, Int):    " + Objects.hash(1,2,3,4));

Running the adapted and enhanced version of the code provided by the commenter leads to this output (with the examples I added highlighted):

Arrays.hashCode(int[]):              955331
Objects.hash(int, int, int, int):    955331
Objects.hash(int[]):                 897913763
Objects.hashCode(Object):            897913732
int[].hashCode():                    897913732
Arrays.hashCode(Int, Int, Int, Int): 955331
Objects.hash(Int, Int, Int, Int):    955331

Comparing the output to the code that generated it quickly shows that Arrays.hashCode(int[]) generates the same hash code value as Objects.hash(Object...) when the elements of the array of int values are passed to that latter method as individual elements. However, we can also see that when the array of primitive int values is passed in its entirety (as a single array instead of as the individual elements of the array), the Objects.hash(Object...) methods generates an entirely different hash code. The other two examples that I added (that are highlighted) are to show what the "direct" hash code is on the array of primitive int values by calling .hashCode() directly on the array or by getting the equivalent result via Objects.hashCode(Object). [It's not a coincidence that the hash code generated by Objects.hash(Object...) for the array of primitive int values is exactly 31 greater than the "direct" hash code generated for the array of primitive int values.]

All of this points to the real issue here: it is typically best to not pass an array of primitives to a method that accepts variable arguments (advertises ellipsis). SonarSource Rules Explorer (Java) provides more details on this in RSPEC-3878. What is particularly relevant in that rule description is the question related to ambiguity, "Is the array supposed to be one object or a collection of objects?"

The answer to the question just posed is that when the array of primitive int values is passed to the variable arguments accepting method Objects.hash(Object...), the entire array is treated as a single Object. In contrast, when an array of reference objects (such as Integer) is passed to that same method, it sees it as the same number of objects being passed to it as elements in the array. This is demonstrated by the next code listing and associated output.

package dustin.examples.hashcodes;

import static java.lang.System.out;

/**
 * Demonstrates the difference in handling of arrays by methods that
 * accept variable arguments (ellipsis) when the arrays have primitive
 * elements and when arrays have reference object elements.
 */
public class ArraysDemos
{
   private static void printEllipsisContents(final Object ... objects)
   {
      out.println("==> Ellipsis Object... - Variable Arguments (" + objects.length + " elements): " + objects.getClass() + " - " + objects);
   }

   private static void printArrayContents(final Object[] objects)
   {
      out.println("==> Array Object[] - Variable Arguments (" + objects.length + " elements): " + objects.getClass() + " - " + objects);
   }

   private static void printArrayContents(final int[] integers)
   {
      out.println("==> Array int[] - Variable Arguments (" + integers.length + " elements): " + integers.getClass() + " - " + integers);
   }

   public static void main(final String[] arguments)
   {
      final int[] primitiveIntegers = ArraysCreator.createArrayOfInts();
      final Integer[] referenceIntegers = ArraysCreator.createArrayOfIntegers();
      out.println("\nint[]");
      printEllipsisContents(primitiveIntegers);
      printArrayContents(primitiveIntegers);
      out.println("\nInteger[]");
      printEllipsisContents(referenceIntegers);
      printArrayContents(referenceIntegers);
   }
}
int[]
==> Ellipsis Object... - Variable Arguments (1 elements): class [Ljava.lang.Object; - [Ljava.lang.Object;@2752f6e2
==> Array int[] - Variable Arguments (10 elements): class [I - [I@1cd072a9

Integer[]
==> Ellipsis Object... - Variable Arguments (10 elements): class [Ljava.lang.Integer; - [Ljava.lang.Integer;@7c75222b
==> Array Object[] - Variable Arguments (10 elements): class [Ljava.lang.Integer; - [Ljava.lang.Integer;@7c75222b

The example code and associated output just shown demonstrate that the method expecting variable arguments sees an array of primitive values passed to it as a single element array. On the other hand, the same method sees an array passed to it with reference object types as being an array with the same number of elements.

Returning to the hash code generation examples with this in mind, the different hash code generated by Objects.hash(Object...) for an array of primitive int values than that generated by Arrays.hashCode(int[]) makes sense. Similarly, we now can explain why the arrays of object references lead to the same hash code regardless of which of those methods is called.

I mentioned earlier that it's not a coincidence that the hash code generated by Objects.hash(Object) is exactly 31 higher than the "direct" hash code of the overall array. This was not surprising because the OpenJDK implementation of Objects.hash(Object...) delegates to Arrays.hashCode(Object[]), which uses 31 as the prime number it multiplies by each element in the calculated hash code. The hash code value provided by Objects.hash(Object...) for an array of primitive int values appears to be exactly what the method's implementation would lead us to expect with the above observations in mind: the direct hash value of the overall array plus the 31 prime number. When that hash code method only loops over a single element (which is the case for an array of primitives passed to a method expecting variable arguments), its calculation is essentially 31 * 1 + <directHashValueOfOverallArray>.

It's worth noting here that even though an array of reference objects had its hash code calculated to the same result as when the elements were passed to the method accepting variable arguments, it is still probably best to avoid passing an array of reference objects to such a method. The javac compiler provides this warning when this occurs: "warning: non-varargs call of varargs method with inexact argument type for last parameter" and adds these useful details about potential ways to address this: "cast to Object for a varargs call" or "cast to Object[] for a non-varargs call and to suppress this warning". Of course, with JDK 8 and later, it's fairly straightforward to process an array in various other ways before providing it to a method expecting variable arguments.

I added a final paragraph to my original post (and its DZone-syndicated version) to attempt to quickly address this, but I have used this post to express this information in greater detail. The specific lessons learned here can be summarized as "Favor the appropriate overloaded Arrays.hashCode method for an array of primitives instead of using Objects.hash(Object...)" and "Favor Arrays.hashCode(Object[]) for arrays of reference types instead of using Objects.hash(Object...)." The more general guidelines are to be wary of passing an array of primitive values to a method expecting variable arguments of type Object if the number of elements the invoked method "sees" is important in any way and to be wary of passing an array of reference objects to a method expecting variable arguments to avoid compiler warnings and the ambiguity being warned about.

Thursday, September 13, 2018

JDK 12 News (13 September 2018)

With General Availability of JDK 11 planned for later this month (25 September 2018), it's a good time to start looking more closely at JDK 12.

In a message titled "Proposed schedule for JDK 12" on the OpenJDK jdk-dev mailing list, Mark Reinhold announced, "With JDK 11 nearly out the door, here's a proposed schedule for JDK 12." The schedule for JDK 12 proposed in that message includes the "Release-Candidate Phase" starting on 31 January 2019 and "General Availability" of JDK 12 on 19 March 2019.

There are already two JEPs targeted for JDK 12 and both of them are "preview features" (my previous blog posts on these JEPs are listed as sub-bullets):

JDK 12 Early Access Build 11 was also released today. Build 11 addresses several minor issues and implements multiple minor changes.

Wednesday, September 12, 2018

Arrays.hashCode(Object[]) versus Objects.hash(Object...)

Since JDK 1.5, the Arrays class has offered overloaded static methods with the name "hashCode"​. Most of the overloaded methods accept an array of a particular primitive type, but the Arrays.hashCode(Object[]) method can be used to calculate an int hash code for an array of reference types. Since its JDK 1.7 inception, the Objects class has provided a method called hash(Object...) that also returns an int hash code for a provided array of Java objects (the ellipsis [...] representing Java varargs is handled as an array and accepts an array). This post provides a brief comparison between Arrays.hashCode(Object) and Objects.hash(Object...).

We can look at the code in OpenJDK to see how OpenJDK implements the two methods being compared here. It turns out that Arrays.hashCode(Object[]) and Objects.hash(Object...) behave exactly the same way because Objects.hash(Object...) completely delegates to Arrays.hashCode(Object[]). This is shown in the next code listing extracted from the OpenJDK Objects.java class.

public static int hash(Object... values) {
    return Arrays.hashCode(values);
}

So, it turns out that the methods are really the same when one or more individual object references are passed. So, for many cases, whichever you choose is mostly a matter of taste. It may appeal to some to use the Arrays method directly given that's what's going to be called anyway. It is typically preferable to use the Arrays method when passing it a construct that is already known to be a Java array and to use the Objects method for situations where the values are being passed in a comma-separated combination without explicit array syntax being required (such as the case of implementing a custom class's hashCode() method and passing that class's attributes of arbitrary types for the hash code computation). When using an array of primitives of the same type, it is typically better to use the appropriate version of Arrays.hashCode for that particular primitive.

The simple class shown in the next code listing (and available on GitHub) demonstrates the differences and similarities in output between the overloaded versions of Arrays.hashCode and the Objects.hash(Object...) method.

package dustin.examples.hashcodes;

import java.util.Arrays;
import java.util.Objects;

import static java.lang.System.out;

/**
 * Demonstration that writes output to standard output with
 * hash codes generated for the same underlying array data by
 * both {@code Arrays.hashCode(Object[])} and by
 * {@code Objects.hash(Object...)}.
 */
public class HashesComparedDemo
{
   public static void main(final String[] arguments)
   {
      final int[] integers = ArraysCreator.createArrayOfInts();
      out.println("Arrays.hashCode(int[]) for int[]: " + Arrays.hashCode(integers));
      out.println("Objects.hash(Object...) for int[]:   " + Objects.hash(integers));
      out.println("Objects.hashCode(Object) for int[]:  " + Objects.hashCode(integers));

      final Integer[] refIntegers = ArraysCreator.createArrayOfIntegers();
      out.println("Arrays.hashCode(Object[]) for Integer[]: " + Arrays.hashCode(refIntegers));
      out.println("Objects.hash(Object...) for Integer[]:   " + Objects.hash(refIntegers));
      out.println("Objects.hashCode(Object) for Integer[]:  " + Objects.hashCode(refIntegers));

      final String[] strings = ArraysCreator.createArrayOfStrings();
      out.println("Arrays.hashCode(Object[]) for String[]: " + Arrays.hashCode(strings));
      out.println("Objects.hash(Object...) for String[]:   " + Objects.hash(strings));
      out.println("Objects.hashCode(Object) for String[]:  " + Objects.hashCode(strings));
   }
}

The code shown above passes three common data sets (an array of primitive int values, an array of reference Integer values, and an array of String values) to the methods Arrays.hashCode, Objects.hash(Object...), and the Objects.hashCode(Object) method that accepts a single Object (of which an overall array qualifies). The simple example then writes the respective hash code values generated by each method for each data set to standard output. The results of running this code are shown next.

Arrays.hashCode(int[]) for int[]: 1722319241
Objects.hash(Object...) for int[]:   356573628
Objects.hashCode(Object) for int[]:  356573597
Arrays.hashCode(Object[]) for Integer[]: 1722319241
Objects.hash(Object...) for Integer[]:   1722319241
Objects.hashCode(Object) for Integer[]:  1735600054
Arrays.hashCode(Object[]) for String[]: 448603921
Objects.hash(Object...) for String[]:   448603921
Objects.hashCode(Object) for String[]:  21685669

As we would expect, Arrays.hashCode(Object[]) and Objects.hash(Object...) return the same calculated hash code for the reference types Integer and String because they both effectively are the implementation of Arrays.hashCode(Object[]). The array of primitive int values leads to different results from Arrays.hashCode(int[]) than from Objects.hash(Object...) and this is, of course, because the array of primitives is passed to an overloaded Arrays.hashCode(int[]) method specifically implemented for that primitive data type rather than to Arrays.hashCode(Object[]).

If one compares the implementation of Arrays.hashCode(int[]) to the implementation of Objects.hash(Object...) delegated to Arrays.hashCode(Object[]), the implementations look essentially the same in terms of logic. The reason for the different result in the case of an array of primitive int values passed to Arrays.hashCode(int[]) when compared to the result from passing that same array of primitive int values to the Objects.hash(Object...) method is that the entire array of int values is treated as a single Object rather than as an array of individual objects when passed to Objects.hash(Object...). Favor the appropriate overloaded Arrays.hashCode method for an array of primitives instead of using Objects.hash(Object...) and favor Arrays.hashCode(Object[]) for arrays of reference types instead of using Objects.hash(Object...) to avoid compiler warnings and associated ambiguity.