Friday, August 17, 2018

Carefully Specify Multiple Resources in Single try-with-resources Statement

One of the more useful new features of Java 7 was the introduction of the try-with-resources statement [AKA Automatic Resource Management (ARM)]. The attractiveness of the try-with-resources statement lies in its promise to "ensure that each resource is closed at the end of the statement." A "resource" in this context is any class that implements AutoCloseable and its close() method and is instantiated inside the "try" clause of the try-with-resources statement.

The Java Language Specification [JLS] describes the try-with-resource statement in detail in Section 14.20.3 (of Java SE 10 JLS in this case). The JLS states that the "try-with-resources statement is parameterized with local variables (known as resources) that are initialized before execution of the try block and closed automatically, in the reverse order from which they were initialized, after execution of the try block."

The JLS clearly specifies that multiple resources can be defined in relation to a single try-with-resources statement and it specifies how multiple resources are specified. Specifically it indicates that try can be followed by a "ResourceSpecification" that is composed of a "ResourceList" that is composed of one or more "Resource"s. When there is more than a single declared resource, the multiple resources are delimited by semicolon (;). This specification of multiple resources in semicolon-delimited list is important because any candidate resources not declared in this manner will not be supported (will not be closed automatically) by the try-with-resources statement.

The most likely source of errors when specifying multiple resources in a try-with-resources statement is "nesting" instantiations of "resources" instead of explicitly instantiating local variables of each of them separately with semicolons between each instantiation. Examples that follow will illustrate the difference.

Two ridiculous but illustrative classes are shown next. Each class implements AutoCloseable and so can be used in conjunction with try-with-resources and will have its close() method called automatically when used correctly with the try-with-resources statement. They are named to reflect that the OuterResource can be instantiated with an instance of the InnerResource.

InnerResource.java

package dustin.examples.exceptions;

import static java.lang.System.out;

public class InnerResource implements AutoCloseable
{
   public InnerResource()
   {
      out.println("InnerResource created.");
   }

   public InnerResource(
      final RuntimeException exceptionToThrow)
   {
      throw  exceptionToThrow != null
         ? exceptionToThrow
         : new RuntimeException("InnerResource: No exception provided.");
   }

   @Override
   public void close() throws Exception
   {
      out.println("InnerResource closed.");
   }

   @Override
   public String toString()
   {
      return "InnerResource";
   }
}

OuterResource.java

package dustin.examples.exceptions;

import static java.lang.System.out;

public class OuterResource implements AutoCloseable
{
   private final InnerResource wrappedInnerResource;

   public OuterResource(final InnerResource newInnerResource)
   {
      out.println("OuterResource created.");
      wrappedInnerResource = newInnerResource;
   }

   public OuterResource(
      final InnerResource newInnerResource,
      final RuntimeException exceptionToThrow)
   {
      wrappedInnerResource = newInnerResource;
      throw  exceptionToThrow != null
           ? exceptionToThrow
           : new RuntimeException("OuterResource: No exception provided.");
   }

   @Override
   public void close() throws Exception
   {
      out.println("OuterResource closed.");
   }

   @Override
   public String toString()
   {
      return "OuterResource";
   }
}

The two classes just defined can now be used to demonstrate the difference between correctly declaring instances of each in the same try-with-resources statement in a semicolon-delimited list and incorrectly nesting instantiation of the inner resource within the constructor of the outer resource. The latter approach doesn't work as well as hoped because the inner resource without a locally defined variable is not treated as a "resource" in terms of invoking its AutoCloseable.close() method.

The next code listing demonstrates the incorrect approach for instantiating "resources" in the try-with-resources statement.

Incorrect Approach for Instantiating Resources in try-with-resources Statement

try (OuterResource outer = new OuterResource(
        new InnerResource(), new RuntimeException("OUTER")))
{
   out.println(outer);
}
catch (Exception exception)
{
   out.println("ERROR: " + exception);
}

When the code above is executed, the output "InnerResource created." is seen, but no output is ever presented related to the resource's closure. This is because the instance of InnerResource was instantiated within the call to the constructor of the OuterResource class and was never assigned to its own separate variable in the resource list of the try-with-resource statement. With a real resource, the implication of this is that the resource is not closed properly.

The next code listing demonstrates the correct approach for instantiating "resources" in the try-with-resources statement.

Correct Approach for Instantiating Resources in try-with-resources Statement

try(InnerResource inner = new InnerResource();
    OuterResource outer = new OuterResource(inner, new RuntimeException("OUTER")))
{
   out.println(outer);
}
catch (Exception exception)
{
   out.println("ERROR: " + exception);
}

When the code immediately above is executed, the output includes both "InnerResource created." AND "InnerResource closed." because the InnerResource instance was properly assigned to a variable within the try-with-resources statement and so its close() method is properly called even when an exception occurs during its instantiation.

The try-with-resources Statement section of the Java Tutorials includes a couple of examples of correctly specifying the resources in the try-with-resources as semicolon-delimited individual variable definitions. One example shows this correct approach with java.util.zip.ZipFile and java.io.BufferedWriter and another example shows this correct approach with an instances of java.sql.Statement and java.sql.ResultSet.

The introduction of try-with-resources in JDK 7 was a welcome addition to the language that it made it easier for Java developers to write resource-safe applications that were not as likely to leak or waste resources. However, when multiple resources are declared within a single try-with-resources statement, it's important to ensure that each resource is individually instantiated and assigned to its own variable declared within the try's resource specifier list to ensure that each and every resource is properly closed. A quick way to check this is to ensure that for n AutoCloseableimplementing resources specified in the try, there should be n-1 semicolons separating those instantiated resources.

Wednesday, August 8, 2018

APIs To Be Removed from Java 11

After seeing several APIs removed as part of Java 10, Java 11 (JSR 384) looks to remove some more APIs. In the recent OpenJDK java-se-spec-experts mailing list post "JSR 384 (Java SE 11) PFD Specification posted to jcp.org," Iris Clark announced the availability of the Java SE 11 (18.9) Proposed Final Draft Specification. This document lists APIs that are being removed as part of Java 11.

"Individual" (class/method) APIs are being removed in addition to the removal of entire modules.

Individual APIs Being Removed in JDK 11
Class/Method Being RemovedAdditional Notes / References
java.lang.Runtime.runFinalizersOnExit(boolean) Dangerous runFinalizersOnExit
Deprecating Java's Finalizer
java.lang.SecurityManager.checkAwtEventQueueAccess() Security Managers and Java SE JDK
JDK-8177554
JDK-8029886
JDK-8186535
java.lang.SecurityManager.checkMemberAccess(java.lang.Class,int)
java.lang.SecurityManager.checkSystemClipboardAccess()
java.lang.SecurityManager.checkTopLevelWindow(java.lang.Object)
java.lang.System.runFinalizersOnExit(boolean) Dangerous runFinalizersOnExit
Deprecating Java's Finalizer
java.lang.Thread.destroy() Thread Methods destroy() and stop(Throwable) Removed in JDK 11
java.lang.Thread.stop(java.lang.Throwable)

Module-level APIs Being Removed from Java 11
Name Module Removed Potential Third Party Replacement
JavaBeans Activation Framework (JAF) java.activation Maven Artifact
Common Object Request Broker Architecture (CORBA) java.corba glassfish-corba
Aggregator Module for other modules listed in this table java.se.ee  
Java Transaction API (JTA) java.transaction Maven Artifact
Java Architecture for XML Binding (JAXB) java.xml.bind Maven Artifact
Java API for XML Web Services (JAX-WS) java.xml.ws Maven Artifact
Common Annotations java.xml.ws.annotation Maven Artifact

JEP 320 ["Remove the Java EE and CORBA Modules"] and the StackOverflow page "Replacements for deprecated JPMS modules with Java EE APIs" provide significantly more details on replacements for the Java SE EE/CORBA-related modules.

Tuesday, August 7, 2018

JDK 12, Merging Collectors, and the Challenge of Naming

It appears likely that a new method will be available on the java.util.streams.Collectors class in JDK 12 that will, according to the new method's proposed Javadoc-based documentation, "Return a Collector that passes the input elements to two specified collectors and merges their results with the specified merge function." The currently proposed name of this new Collectors method is pairing, but that new method's name has been the source of significant discussion.

The naming of this method has solicited wide discussion on the OpenJDK core-libs-dev mailing list. Although it would be easy at first thought to label this an example of bike-shedding (or Parkinson's Law of Triviality), my experience has been that proper naming can be more important than it might first seem. I've seen many situations in which there was nothing wrong with the logic of a particular implementation, but problems ensued related to use of that implementation due to miscommunication or bad assumptions tied to poorly named code constructs. For a major API in the JDK, it's not so surprising after all that the name of this method parameter would be so seriously considered.

The discussion began with Peter Levart's post "BiCollector" (June 17), in which he opened with the question, "Have you ever wanted to perform a collection of the same Stream into two different targets using two Collectors?" Levart included an example of an implementation of such a "BiCollector" and asked if this was the type of thing that might be added to the JDK. Not surprisingly, it turns out that this is desired by others and some alternate existing implementations (Kirk Pepperdine and Tagir Valeev's streamex implementation) were mentioned.

After discussion regarding the multiple implementations of the "BiCollector," Tagir Valeev created an OpenJDK "preliminary webrev of my own implementation" and put it out for review (June 15). In that post, Valeev specifically called out that he had made up the name "pairing" for the method and added, "as I'm not a native English speaker I cannot judge whether it's optimal, so better ideas are welcome." That "opened the flood gates!"

Although there was some interesting and significant discussion surrounding other implementation details of the proposed "BiCollector" (now in proposed code as "Collectors.pairing(...)," the naming of the method received the most contributions. In a June 21 post, Valeev summarized the proposed names with accompanying comments about each recommendation and I have reproduced that list (but without the insightful comments) here:

For those interested in arguments "for" and "against" the above proposed names, I recommend viewing Valeev's original post. Most of the posts linked to above with the name suggestions provide arguments for their favored name and there is some interesting insight into what OpenJDK contributors think what aspects in a method name might aid or hinder understanding of the method.

After the excitement of naming the method, discussion died down for a while on this addition to the Collectors API until Valeev posted a "ping message" today with a link to the latest webrev for review (changes @since 11 to @since 12). In response to this "ping" message, there is feedback regarding the name of the last argument to the proposed method (currently named "finisher"), which is another reminding of the importance of naming to many of us.

Other posts on this topic on the core-libs-dev mailing list remind us that for this new method to be added to the Collectors public API, a few things still need to happen that include a sponsor volunteering to review and sponsor the change set as well as the need for a CSR (Compatibility & Specification Review) and "a couple of reviewers that are fully aware of Streams design."

A Brian Goetz post on this thread summarizes why naming this proposed method is so difficult:

The essential challenge in naming here is that this Collector does two (or maybe three) things: duplicate the stream into two identical streams ("tee"), sends each element to the two collectors ("collecting"), and then combines the results ("finishing"). So all the one-word names (pairing, teeing, unzipping, biMapping) only emphasize one half of the operation, and names that capture the full workflow accurately (teeingAndCollectingAndThen) are unwieldy.

That same Goetz post argues against "merging" (or its derivatives) for the method's name because "names along the lines of 'merging' may incorrectly give the idea that the merge is happening elementwise, rather than duplicating the streams, collecting, and merging the results."

I find several of the proposed method names to be reasonable, but there a couple that I believe (hope) were made out of an attempt at humor.

JDK-8205461 ["Create Collector which merges results of two other collectors"] is the "Enhancement" "bug" describing this issue. Its description currently begins with, "Add a new Collector into Collectors class which merges results of two other collectors" before explicitly stating, "One API method should be added (name is subject to discussion)." If you've ever wanted to name a method in a public JDK API, this might be your opportunity!

I have used this blog post in attempt to accomplish two things:

  1. Create awareness of this method that is likely to be available in the public API as of JDK 12
  2. Present an example of why naming is important and why it can be as difficult as the technical implementation
    • Proper naming can be difficult for anyone, even those of us who are native English speakers!

Although one or more names in the implementation may change, the currently proposed implementation is logically likely very close to what will eventually be delivered in conjunction with JDK-8205461.

Saturday, August 4, 2018

Project Valhalla: A First Look at L-World Value Types

In the post "JVM Language Summit 2018 and Valhalla EA Build 0", I mentioned that Project Valhalla's "L-World Value Types" Early-Access Builds are now available for Linux/x64, macOS/x64, and Windows/x64. Specifically, "Build 0 (2018/7/30)" is available for download as a "convenience." In that same post, I also mentioned that the JVM Language Summit 2018 had just wrapped up and I provided a link to one of that event's presentations: "LWorld: the next steps on the journey to Valhalla". In this post, I use code based on the Project Valhalla "L-World Value Types" Early-Access Build 0 to illustrate some of the points made in the JVM Language Summit 2018 presentation on early versions of L-World.

CAUTION: The build discussed in this post is "intended for expert users interested in Project Valhalla", is NOT intended for production, and has severe limitations and disclaimers associated with it. This build is primarily intended for those who want to "play" with L-World value types and not for other more general uses. In announcing this build on the valhalla-dev OpenJDK mailing list, David Simms described this Build 0 as follows:

"The first truly usable value type prototype" with experimental language support. Based on JDK mainline, almost complete JDK 11. This is build "0", there are bugs, performance issues, and usability issues.

The following code listing (including the __ByValue) compiles against the L-World Value Types Early Access Build 0:

package dustin.examples.valhalla;

public final __ByValue class DoubleComplex
{
   public final double real;
   public final double imaginary;
   public DoubleComplex(final double newReal, final double newImaginary)
   {
      this.real = newReal;
      this.imaginary = newImaginary;
   }
}

The L-World Value Types Early Access Build 0 javac compiler adds some methods to the DoubleComplex class shown above beyond those added by the compiler in other versions of Java. These are perhaps most easily identified by running javap against the generated class.

As the above screen snapshot demonstrates, javap tells us that several methods were added to the DoubleComplex.class class file generated from the DoubleComplex.java source file by the L-World Value Types Early Access Build 0 javac compiler:

Compiled from "DoubleComplex.java"
public final value class dustin.examples.valhalla.DoubleComplex {
  public final double real;
  public final double imaginary;
  public dustin.examples.valhalla.DoubleComplex(double, double);
  public final int hashCode();
  public final boolean equals(java.lang.Object);
  public final java.lang.String toString();
  public final long longHashCode();
  public static dustin.examples.valhalla.DoubleComplex $makeValue$(double, double);
}

Normally, we'd only expect the javap output of a .class file generated from the .java file shown above to include the two fields and the constructor that are present in the source Java file. However, the L-World Value Types Early Access Build 0 javac compiler generated a .class file with a hashCode() implementation, an equals(Object) implementation, a toString() implementation, a longHashCode() implementation (that returns long instead of the int returned by standard hashCode()), and a mysterious-looking static method $makeValue$ because of the __ByValue reference in the source code. I wasn't able to get __MakeValue to work for me in creating an instance of this value type, but I will demonstrate the other added methods in this generated class file.

I will show some output of these methods generated on value type DoubleComplex that were not explicitly specified in the Java source code file. For these output examples, the following three instances of the DoubleComplex will be used:

private final static DoubleComplex complex1
   = new DoubleComplex(15.0, 25.0);
private final static DoubleComplex complex2
   = new DoubleComplex(25.0, 35.0);
private final static DoubleComplex complex3
   = new DoubleComplex(25.0, 35.0);

The second and third instances (complex2 and complex3) have the same values and the complex1 instance has different values. Based on these instances, the methods added to ComplexDemo by the L-World Value Types EA Build 0 javac compiler generate results that look like the following:

Examples of Methods Added to Value Type)
Method Added to Value Type Results for Instances of DoubleComplex Value Type
(methods' output in bold
toString() [value class dustin.examples.valhalla.DoubleComplex, 15.0, 25.0]
[value class dustin.examples.valhalla.DoubleComplex, 25.0, 35.0]
[value class dustin.examples.valhalla.DoubleComplex, 25.0, 35.0]
equals(Object) Comparing [value class dustin.examples.valhalla.DoubleComplex, 15.0, 25.0] to [value class dustin.examples.valhalla.DoubleComplex, 25.0, 35.0]: false
Comparing [value class dustin.examples.valhalla.DoubleComplex, 25.0, 35.0] to [value class dustin.examples.valhalla.DoubleComplex, 25.0, 35.0]: true
hashCode() Complex1.hashCode(): -478263309
Complex2.hashCode(): -455358477
Complex3.hashCode(): -455358477
longHashCode() Complex1.longHashCode(): 1610134472691
Complex2.longHashCode(): 1610157377523
Complex3.longHashCode(): 1610157377523

The table above demonstrates that reasonable implementations of toString(), equals(Object), and hashCode() are provided by default for Java value types compiled with the L-World Value Types Early Access Build 0.

To run code that used my value type, I needed to use the flag -XX:+EnableValhalla in addition to specifying the JVM flag --enable-preview. If I failed to supply the -XX:+EnableValhalla flag to the L-World Value Types Early Access Build 0 java launcher, I was presented with the error message

Exception in thread "main" java.lang.ClassFormatError: Class modifier ACC_VALUE in class dustin/examples/valhalla/DoubleComplex requires option -XX:+EnableValhalla

Things You Cannot Do with Value Types in L-World Value Types EA Build 0

There are some interesting things you cannot do with the value types created with L-World Value Types Early Access Build 0 (several of these are intentional and likely to not be changed):

  • Compare two value types with ==
    • Compile-time error: "error: value types do not support =="
  • Pass value type to System.identityHashCode(Object)
    • Compile-time error: "error: value types do not support identityHashCode"
  • Synchronize on a value type
    • Compile-time error:
      error: unexpected type
           synchronized (complex1)
           ^
             required: reference
             found:    DoubleComplex
  • Value Type cannot extend another class
    • Compile-time error: "error: value type may not extend another value or class"

Class.isValue()

Although I don't demonstrate it here, there is a method available on the java.lang.Class class with this L-World Value Types Early Access Build 0 that indicates whether the class is a value type class or not. The method, Class.isValue(), returns true if the class is a value type class or false if it is NOT a value type class.

The isValue() method also appears to throw InternalErrors if it is called upon a class that is internally labeled a value type but whose Modifiers indicate it is also an interface, an abstract class, or extends a class other than Object. This implies, of course, that a value type class cannot be declared abstract ("error: illegal combination of modifiers: abstract and final" or "error: illegal combination of modifiers: abstract and value") or be an interface ("error: illegal combination of modifiers: interface and value").

L-World's Future

Although significant progress has been made in Project Valhalla related to Value Types, there is still much work to come. The JVM Language Summit presentation I cited earlier ends with discussion about "L-World major milestones" in the slides titled "L-World Roadmap." These slides and the speakers discuss major milestones "LW1", "LW10", and "LW100" and the features and characteristics expected for each of these major milestones. There will, of course, be milestones between those numbers as well. The availability of L-World Value Types Early Access Build 0 provides a convenient mechanism for interested parties to start playing with L-World value types.

Wednesday, August 1, 2018

JDK 11: Taking Single-File Java Source-Code Programs Out for a Spin

The JDK 11 Early Access Builds include functionality related to JEP 330 ("Launch Single-File Source-Code Programs"). I have written about JEP 330 before in posts "Shebang Coming to Java?" and "JEP 329 and JEP 330 Proposed for JDK 11". I get to take this feature out for a spin in this post thanks to the JDK 11 Early Access Builds.

For this demonstration, I'm using the latest (as of this writing) OpenJDK JDK 11 Early Access Build 24.

One of the first indications that support for JEP 330 is included with this JDK distribution is seen when using the -help flag (java -help):

As shown in the last image, the "help" starts with a "usage" statement and the last example in the usage statement describes how to use the Java launcher (java) to run single-file source-code programs. Specifically, the output shows the following "usage" with the usage that is the subject of this post highlighted here:

Usage: java [options] <mainclass> [args...]
           (to execute a class)
   or  java [options] -jar <jarfile> [args...]
           (to execute a jar file)
   or  java [options] -m <module>[/<mainclass>] [args...]
       java [options] --module <module>[/<mainclass>] [args...]
           (to execute the main class in a module)
   or  java [options] <sourcefile> [args]
           (to execute a single source-file program)

To demonstrate this feature, I'm going to use a simple example adapted (very slightly) from that provided in the 24 May 2018 Mario Torre post on the OpenJDK jdk-dev mailing list.

helloYou.jv

#!/bin/java
public class Hello
{
   public static void main(final String[] args)
   {
      final String name = System.console().readLine("\nPlease enter your name: ");
      System.console().printf("Hello, %s!%n", name);
   }
}

I have called this file helloYou.jv. Note that it does NOT end with the .java extension that regular Java source code files end with and I did not match the name of the file to the name of the class. In fact, I started the file's name with a lower case letter!

When I try to run this file directly with OpenJDK 11 EA-24, I see an error ("Could not find or load main class helloYou.jv"):

The following screen snapshot demonstrates that it works when I pass the flag --source=11 to the Java launcher.

I highlighted in my post "Shebang Coming to Java?" that it sounded like single-file source programs used with this JEP 330 support were not going to be allowed to end with the .java extension (which extension would be reserved for traditional Java source files). This seems to be the case as shown in the next screen snapshot where I attempt to run this feature against the same code as above, but now with the file name helloYou.java.

The last image demonstrates that we cannot run .java files with a shebang because they are treated as regular Java files and thus must meet the specification of regular Java source code files.

With this early access build, if I comment out the shebang line, I can run the now traditionally compliant Java single source code file helloYou.java (even with the .java extension and without the flag --source=11).

Had I attempted that last maneuver with OpenJDK JDK 10, attempting to run a Java source code file like that just shown would produce the error message discussed earlier: "Error: Could not find or load main class helloYou.java". I would have needed to compile the Java source code file into a .class file and would have needed to make sure it was on the classpath of the Java launcher.

This post has been a first look at the feature single-file source-code programs that is now available in the JDK 11 Early Access Builds.