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.

Tuesday, July 31, 2018

JVM Language Summit 2018 and Valhalla EA Build 0

July 2018 ended with some interesting developments related to the future of Java and the JVM. JVM Language Summit 2018 was held at Oracle's Santa Clara campus on the last two days of the month and Build 0 of the Project Valhalla "L-World Value Types" Early-Access Builds was released on July 30.

JVM Language Summit 2018

Videos of presentations from the JVM Language Summit 2018 are available on YouTube. The easiest way to access these videos is via the JVM Language Summit 2018 Playlist. The recorded presentations include the following:

Valhalla Early-Access Builds: Build 0

The Project Valhalla page now offers an early access build of the Valhalla Project. This first early access build, Build 0, was posted on July 30. The first three paragraphs of the page with this Build 0 tell us that this build is "aimed at testing a 'Value Types' implementation within the JVM" (L-World Value Types), is "provided as a convenience so that they [expert users interested in Project Valhalla] don't need to build from the source code (branch 'lworld')", and is "based on an incomplete version of JDK 11."

The Build 0 Project Valhalla Early Access Build is available as a gzip-ed TAR file for Linux/x64, Windows/x64, and macOS/x64. Although there is a long list of limitations associated with this Build 0 early access build, I'm still looking forward to playing with it.

Monday, July 30, 2018

Memory-Hogging Enum.values() Method

I'm a big fan of Java's enum. It seemed like we waited forever to get it, but when we did finally get it (J2SE 5), the enum was so much better than that provided by C and C++ that it seemed to me "well worth the wait." As good as the Java enum is, it's not without issues. In particular, the Java enum's method values() returns a new copy of an array representing its possible values each and every time it is called.

The Java Language Specification spells out enum behavior. In The Java Language Specification Java SE 10 Edition, it is Section 8.9 that covers enums. Section 8.9.3 ("Enum Members") lists two " implicitly declared methods": public static E[] values() and public static E valueOf(String name). Example 8.9.3-1 ("Iterating Over Enum Constants With An Enhanced for Loop") demonstrates calling Enum.values() to iterate over an enum. The problem, however, is that Enum.values() returns an array and arrays in Java are mutable [Section 10.9 ("An Array of Characters Is Not a String") of the Java Language Specification reminds us of this when differentiating between a Java string and a Java array of characters.]. Java enums are tightly immutable, so it makes sense that the enum must return a clone of the array returned by the values() method each time that method is called to ensure that the array associated with the enum is not changed.

A recent post on the OpenJDK compiler-dev mailing list titled "about Enum.values() memory allocation" observes that "Enum.values() allocates a significant amount of memory when called in a tight loop as it clones the constant values array." The poster of that message adds that this "is probably for immutability" and states, "I can understand that." This message also references a March 2012 message and associated thread on this same mailing list.

The two threads on the compiler-dev mailing list include a few interesting currently available work-arounds for this issue.

Brian Goetz's message on this thread starts with the sentence, "This is essentially an API design bug; because values() returns an array, and arrays are mutable, it must copy the array every time." [Goetz also teases the idea of "frozen arrays" (Java arrays made immutable) in that message.]

This issue is not a new one. William Shields's December 2009 post "Mutability, Arrays and the Cost of Temporary Objects in Java" states, "The big problem with all this is that Java arrays are mutable." Shields explains old and well-known problems of mutability in the Java Date class before writing about the particular issue presented b Enum.values():

Java enums have a static method called values() which returns an array of all instances of that enum. After the lessons of the Date class, this particular decision was nothing short of shocking. A List would have been a far more sensible choice. Internally this means the array of instances must be defensively copied each time it is called...

Other references to this issue include "Enums.values() method" (Guava thread) and "Java’s Enum.values() Hidden Allocations" (shows caching the array returned by Enum.values()). There is also a JDK bug written on this: JDK-8073381 ("need API to get enum's values without creating a new array").

Some of the currently available work-arounds discussed in this post are illustrated in the next code listing, which is a simple Fruit enum that demonstrates caching the enum's values in three different formats.

Fruit.java Enum with Three Cached Sets of 'Values'

package dustin.examples.enums;

import java.util.EnumSet;
import java.util.List;

/**
 * Fruit enum that demonstrates some currently available
 * approaches for caching an enum's values so that a new
 * copy of those values does not need to be instantiated
 * each time .values() is called.
 */
public enum Fruit
{
   APPLE("Apple"),
   APRICOT("Apricot"),
   BANANA("Banana"),
   BLACKBERRY("Blackberry"),
   BLUEBERRY("Blueberry"),
   BOYSENBERRY("Boysenberry"),
   CANTALOUPE("Cantaloupe"),
   CHERRY("Cherry"),
   CRANBERRY("Cranberry"),
   GRAPE("Grape"),
   GRAPEFRUIT("Grapefruit"),
   GUAVA("Guava"),
   HONEYDEW("Honeydew"),
   KIWI("Kiwi"),
   KUMQUAT("Kumquat"),
   LEMON("Lemon"),
   LIME("Lime"),
   MANGO("Mango"),
   ORANGE("Orange"),
   PAPAYA("Papaya"),
   PEACH("Peach"),
   PEAR("Pear"),
   PLUM("Plum"),
   RASPBERRY("Raspberry"),
   STRAWBERRY("Strawberry"),
   TANGERINE("Tangerine"),
   WATERMELON("Watermelon");

   private String fruitName;

   Fruit(final String newFruitName)
   {
      fruitName = newFruitName;
   }

   /** Cached fruits in immutable list. */
   private static final List<Fruit> cachedFruitsList = List.of(Fruit.values());

   /** Cached fruits in EnumSet. */
   private static final EnumSet<Fruit> cachedFruitsEnumSet = EnumSet.allOf(Fruit.class);

   /** Cached fruits in original array form. */
   private static final Fruit[] cachedFruits = Fruit.values();

   public static List<Fruit> cachedListValues()
   {
      return cachedFruitsList;
   }

   public static EnumSet<Fruit> cachedEnumSetValues()
   {
      return cachedFruitsEnumSet;
   }

   public static Fruit[] cachedArrayValues()
   {
      return cachedFruits;
   }
}

The fact that Enum.values() must clone its array each time it is called is really not a big deal in many situations. That stated, it's not difficult to envision cases where it would be useful to invoke Enum.values() repeatedly in a "tight loop" and then the copying of the enum values into an array each time would start to have a noticeable impact on memory used and the issues associated with greater memory use. It would be nice to have a standard approach to accessing an enum's values in a more memory efficient manner. The two threads previously mentioned discuss some ideas for potentially implementing this capability.

Monday, July 23, 2018

JDK 11: New Default Collection Method toArray(IntFunction)

The "JDK 11 Early-Access Release Notes" indicate that Early Access Build 20 of JDK 11 includes a new default method on the Collection interface that "allows the collection's elements to be transferred to a newly created array of a desired runtime type". This new default method [Collection.toArray(IntFunction)] works similarly to the same-named method already available on the Stream interface [Stream.toArray​(IntFunction)].

The next code listing demonstrates this new JDK 11 default Collection method in action (on a Set in this case).

final Set<String> names = Set.of("Fred", "Wilma", "Barney", "Betty");
out.println(Arrays.toString(names.toArray(String[]::new)));

Because I used an (unordered) Set, order of the Strings in the generated array can be different than the order the Strings were specified for initialization of the Set. This is demonstrated in the next screen snapshot (which also indicates that I'm using JDK 11 Early Access Build 23 for this example).

Many of us use Java collections more frequently than arrays, but there are times we need to convert these collections to arrays. The default method Collection.toArray(IntFunction) provides a highly convenient mechanism for this. There was already a similar method on Collecton [Collection.toArray(T[])] and the existence of these two methods means it's no longer possible to pass null to either Collection.toArray(-) method (compiler is unable to distinguish them and will report the error message "reference to toArray is ambiguous"). This is not much of a price to pay as both methods throw NullPointerException anyway when null is passed to them.

Saturday, July 21, 2018

Optional.isEmpty() Available in JDK 11 EA Builds

My recently posted question "Optional.isEmpty() Coming to Java?" was prompted by a core-libs-dev mailing list post titled "RFR: 8184693: (opt) add Optional.isEmpty". The current JDK 11 Early Access builds (such as OpenJDK JDK Early Access Build 23 that I use in this post) now include the isEmpty() method on the "Optional" classes Optional, OptionalDouble, OptionalInt, and OptionalLong. This allows for more fluent expression in cases that formerly relied upon negation of Optional.isPresent() [or !OptionalDouble.isPresent(), !OptionalInt.isPresent(), or !OptionalLong.ifPresent()] as was done previously.

The next simple and contrived code listing demonstrates Optional.isEmpty().

public static void demonstrateOptionalIsEmpty()
{
   final Optional<String> middleName = getMiddleName();
   if (middleName.isEmpty())
   {
      out.println("There is no middle name!");
   }
}

Although the same functionality that Optional.isEmpty() provides can be achieved with !Optional.isPresent(), there are advantages to having these types of "isEmpty" methods available in the APIs of commonly used collection and data-holding classes. The ! symbol is more easily missed when reading and reviewing code than is an explicitly named method such as "isEmpty()." Having such a method also aligns Optional's API for detecting "empty" more closely to that provided by String [String.isEmpty()],Collection [Collection.isEmpty()], and Map [Map.isEmpty()].

Monday, July 9, 2018

Deferred Execution with Java's Predicate

In the previous posts "Deferred Execution with Java's Supplier" and "Deferred Execution with Java's Consumer", I looked at easily deferring execution in Java via standard Java APIs that accept, respectively, Suppliers and Consumers. In this post, I take a similar look at how standard JDK-provided APIs allow for deferred execution via the standard functional interface Predicate. The Predicate is described in its Javadoc, "Represents a predicate (boolean-valued function) of one argument." In other words, a Predicate is like a JDK-supplied Function, but with its return value limited to either true or false.

Perhaps the most common application of Predicate in the standard Java APIs is in the context of filters. Several of the examples in this post will demonstrate use of Predicate in conjunction with filtering methods on instances of Optional and on instances of Stream.

Optional.filter(Predicate)

The behavior of the Optional class's filter(Predicate) method is described this way by its Javadoc documentation, "If a value is present, and the value matches the given predicate, returns an Optional describing the value, otherwise returns an empty Optional." In other words, Optional.filter(Predicate) returns an Optional that will be empty if either the original Optional was empty or if the Predicate applied to the original and present Optional resolves to false. Otherwise, if the original Optional does have a "present" value and the Predicate applied to that value returns true, the returned Optional will also have the same "present" value. This is illustrated in the next code listing (full source is available on GitHub).

Optional.filter(Predicate) Demonstrated

/**
 * Demonstrate use of {@code Optional.filter(Predicate)} on an
 * {@code Optional<Boolean>}.
 */
public static void demonstrateOptionalFilterOnBoolean()
{
   out.print("\nfalse: ");
   getOptionalBoolean(false).filter(b -> b).ifPresent(out::print);
   out.print("\ntrue:  ");
   getOptionalBoolean(true).filter(b -> b).ifPresent(out::print);
   out.print("\nnull:  ");
   getOptionalBoolean(null).filter(b -> b).ifPresent(out::print);
}

/**
 * Demonstrate use of {@code Optional.filter(Predicate)} on an
 * {@code Optional<Float>}.
 */
public static void demonstrateOptionalFilterOnFloat()
{
   out.print("\n3.14: ");
   getOptionalFloat(3.14f).filter(f -> f > 0.0).ifPresent(out::print);
   out.print("\n-2.5: ");
   getOptionalFloat(-2.5f).filter(f -> f > 0.0).ifPresent(out::print);
   out.print("\nnull: ");
   getOptionalFloat(null).filter(f -> f > 0.0).ifPresent(out::print);
}

The two methods in the above code listing demonstrate use of Optional.filter(Predicate) on a lambda expression that results in a direct boolean result and on a lambda expression that results in a boolean result based on numerical comparison. In one case, the Predicate is the boolean and in the other case the Predicate is the numeric comparison.

Stream.filter(Predicate)

The Stream interface's method filter(Predicate) works similarly to the Optional class's method of the same name. The next code listing demonstrates application of Stream.filter(Predicate).

Stream.filter(Predicate) Demonstrated

/**
 * Demonstrates use of {@code Stream.filter(Predicate}}.
 */
public static void demonstrateStreamFilter()
{
   final int maximum = 100;
   out.println("\nThe probable prime numbers between 1 and " + maximum + " are:");
   final Stream<BigInteger> bigIntegers = getConsecutiveBigIntegers(maximum);
   bigIntegers.filter(bi -> bi.isProbablePrime(100)).forEach(pp -> out.println(" " + pp));
}

The above code listing is not intended to demonstrate the best approach to identifying prime numbers in Java. Instead, it's intended to demonstrate how filter(Predicate) can be invoked on a Stream to narrow down elements of that Stream to only those matching the Predicate.

For my next illustration of Stream.filter(Predicate), I use the Pattern class's convenient method asPredicate() to supply the instance of the Predicate to be supplied to both examples using Stream.filter(Predicate).

Stream.filter(Predicate) with Pattern.asPredicate() Demonstrated

/**
 * Demonstrates use of {@code Pattern.asPredicate()} to provide
 * a {@code Predicate} that can be used with {@code Stream.filter()}.
 */
public static void demonstratePatternAsPredicateInFilter()
{
   final long count
      = getPotentialTelephoneNumbers().stream()
         .filter(PATTERN.asPredicate())
         .peek(out::println)
         .count();
   out.println(count + " valid telephone numbers.");
}

Collection.removeIf(Predicate)

The Collection interface specifies (and implements as a default method) the useful method removeIf(Predicate). There are also multiple implementations of Collection that implement their own overridden versions of removeIf(Predicate) that include ArrayDeque.removeIf(Predicate), ArrayList.removeIf(Predicate), and Vector.removeIf(Predicate).

The next code listing demonstrates two examples of Collection.removeIf(Predicate) in action. The first example uses the method Predicate.negate() to negate the expected regular expression pattern so that the elements removed from the collection are those that do NOT match the regular expression. The second example performs similar functionality, but takes advantage of the JDK 11-introduced 'not' method to perform this negation.

Collection.removeIf(Predicate) with Negated Pattern.asPredicate() Demonstrated

/**
 * Demonstrates use of {@code Collection.removeIf(Predicate)}
 * in conjunction with {@code Predicate.negate()}.
 */
public static void demonstrateCollectionRemoveIf()
{
   final Set<String> telephoneNumbers = new HashSet<>(getPotentialTelephoneNumbers());
   telephoneNumbers.removeIf(PATTERN.asPredicate().negate());
   out.println(telephoneNumbers);
}

/**
 * Demonstrates use of {@code Collection.removeIf(Predicate)}
 * in conjunction with JDK 11-introduced {@code Predicate.not()}.
 */
public static void demonstrateCollectionRemoveIfWithJdk11Not()
{
   final Set<String> telephoneNumbers = new HashSet<>(getPotentialTelephoneNumbers());
   telephoneNumbers.removeIf(not(PATTERN.asPredicate()));
   out.println(telephoneNumbers);
}

Stream.allMatch(Predicate)

The Stream interface's method allMatch(Predicate) returns true if every single element in the stream matches the provided Predicate. If even a single element does not match the Predicate, the method returns false.

Stream.allMatch(Predicate) Demonstrated

/**
 * Demonstrate use of {@code Stream.allMatch(Predicate)}.
 */
public static void demonstrateStreamAllMatch()
{
   final Set<String> names = getNames();
   final boolean allNamesSixDigits = names.stream()
      .allMatch(name -> name.length() == 6);
   out.println("Are all names " + names + " six digits? " + allNamesSixDigits);
}

Stream.anyMatch(Predicate)

The Stream.anyMatch(Predicate) method returns true if at least one of its elements matches the Predicate and returns false if none of its elements match the Predicate.

Stream.anyMatch(Predicate) Demonstrated

/**
 * Demonstrate use of {@code Stream.anyMatch(Predicate)}.
 */
public static void demonstrateStreamAnyMatch()
{
   final Set<String> names = getNames();
   final boolean anyNamesSixDigits = names.stream()
      .anyMatch(name -> name.length() == 6);
   out.println("Are any names " + names + " six digits? " + anyNamesSixDigits);
}

Stream.noneMatch(Predicate)

The Stream.noneMatch(Predicate) method returns true when no elements in stream match the Predicate and returns false if at least one element in the stream DOES match the Predicate.

Stream.noneMatch(Predicate) Demonstrated

/**
 * Demonstrate use of {@code Stream.noneMatch(Predicate)}.
 */
public static void demonstrateStreamNoneMatch()
{
   final Set<String> names = getNames();
   final boolean noNamesSixDigits = names.stream()
      .noneMatch(name -> name.length() == 6);
   out.println("Are no names " + names + " six digits? " + noNamesSixDigits);
   final boolean noNamesFourDigits = names.stream()
      .noneMatch(name -> name.length() == 4);
   out.println("Are no names " + names + " four digits? " + noNamesFourDigits);
}

Collectors.partitioningBy(Predicate)

Although there are several more JDK APIs that use Predicate, I wrap this post up with discussion of and an example of using Collectors.partitioningBy(Predicate). This interesting method divides up all elements in the stream it is invoked upon into two groups with one group associated with key Boolean.TRUE (elements that match the Predicate) and with one group associated with the key Boolean.FALSE (those elements that did not match the Predicate). The next code listing takes advantage of this to divide integers up into even numbers and odd numbers.

Collectors.partitioningBy(Predicate) Demonstrated

/**
 * Demonstrate use of {@code Collectors.partitioningBy(Predicate)}.
 */
public static void demonstrateCollectorsPartitioningBy()
{
   final Map<Boolean, List<Integer>> evensAndOdds
      = getConsecutiveIntegers(100)
         .collect(Collectors.partitioningBy(integer -> integer % 2 == 0));
   out.println("Evens: " + evensAndOdds.get(Boolean.TRUE));
   out.println("Odds:  " + evensAndOdds.get(Boolean.FALSE));
}

I used several "helper" methods in the above code examples that are not shown in this post. These "helper" methods and all of the examples shown in this post are available on GitHub.

Java's standard functional interface Predicate is a specialized version of fellow built-in Java functional interface Function that arguably deserves its own specialization because the true/false return status is so commonly useful for representing the conditions in which certain functionality applies or does not apply. This post has demonstrated several instances in the JDK where Predicate is used to determine which stream elements apply, whether or not an Optional applies, and to divide up stream elements into those that satisfy the predicate and those that do not. Along the way, convenience methods such as Pattern.asPredicate() and Predicate.not() were also demonstrated.

Thursday, July 5, 2018

Applying New JDK 11 String Methods

In the posts "New Methods on Java String with JDK 11" and "String#repeat Coming to Java?", I discussed six new methods coming to the Java String with JDK 11. The available early access JDK 11 builds already include these new methods and I use one of those early access builds to demonstrate them in this post.

I am using OpenJDK JDK 11 Early Access Build 20 for compiling and running the examples shown in this post.

The six methods added to String for JDK 11 that are demonstrated in this post via the OpenJDK JDK 11 Early Access Build 20 are:

  • String.repeat(int)
  • String.lines()
  • String.strip()
  • String.stripLeading()
  • String.stripTrailing()
  • String.isBlank()

The source code for the examples demonstrated in this post is available on GitHub.

String.repeat(int)

The String.repeat(int) method provides handy functionality that I've wished to see in Java since experiencing this functionality in Groovy. As its name suggests, this method repeats the String it is run against as many times as provided by the int parameter. I will likely use this method frequently in the future when generating simple demonstrations and use it for this post's examples. The next code listing demonstrates use of String.repeat(int) to easily generate header separators for the demonstration output.

Use of String.repeat(int)

/**
 * Write provided {@code String} in header. Note that this
 * implementation uses {@code String.repeat(int)}.
 *
 * @param headerText Title of header.
 */
private static void writeHeader(final String headerText)
{
   final String headerSeparator = "=".repeat(headerText.length()+4);
   out.println("\n" + headerSeparator);
   out.println("= " + headerText + " =");
   out.println(headerSeparator);
}

The writeHeader(String) method uses String.repeat(int) to easily generate "header separator" lines from the "=" character enough times to cover the provided headerText length plus 4 additional characters to allow for an extra "=" and extra space on each side of the "header text". The writeHeader(String) method is used by all the other demonstration examples in this post and so will be demonstrated via those examples.

String.lines()

The String.lines() method splits the String upon which it is called by its line terminators and returns a Stream of Strings as demarcated by those line terminators.

Use of String.lines()

/**
 * Demonstrate method {@code String.lines()} added with JDK 11.
 */
public static void demonstrateStringLines()
{
   final String originalString = prepareStringWithLineTerminators();
   final String stringWithoutLineSeparators
      = originalString.replaceAll("\\n", "\\\\n");
   writeHeader("String.lines() on '"  + stringWithoutLineSeparators  + "'");
   final Stream<String> strings = originalString.lines();
   strings.forEach(out::println);
}

Sample output is shown in the next screen snapshot.

String.strip() / String.stripLeading() / String.stripTrailing()

The String.strip(), String.stripLeading(), and String.stripTrailing() methods trim white space [as determined by Character.isWhiteSpace()] off either the front, back, or both front and back of the targeted String.

Use of String.strip() / String.stripLeading() / String.stripTrailing()

/**
 * Demonstrate method {@code String.strip()} added with JDK 11.
 */
public static void demonstrateStringStrip()
{
   final String originalString = prepareStringSurroundedBySpaces();
   writeHeader("String.strip() on '" + originalString + "'");
   out.println("'" + originalString.strip() + "'");
}

/**
 * Demonstrate method {@code String.stripLeading()} added with JDK 11.
 */
public static void demonstrateStringStripLeading()
{
   final String originalString = prepareStringSurroundedBySpaces();
   writeHeader("String.stripLeading() on '" + originalString + "'");
   out.println("'" + originalString.stripLeading() + "'");
}

/**
 * Demonstrate method {@code String.stripTrailing()} added with JDK 11.
 */
public static void demonstrateStringStripTrailing()
{
   final String originalString = prepareStringSurroundedBySpaces();
   writeHeader("String.stripTrailing() on '" + originalString + "'");
   out.println("'" + originalString.stripTrailing() + "'");
}

When the above code is executed, the output looks like that shown in the next screen snapshot.

String.isBlank()

The String.isBlank() method indicates if the targeted String is empty or contains only white space characters as determined by Character.isWhitespace(int).

Use of String.isBlank()

/**
 * Demonstrate method {@code String.isBlank()} added with JDK 11.
 */
public static void demonstrateStringIsBlank()
{
   writeHeader("String.isBlank()");
   final String emptyString = "";
   out.println("Empty String -> " + emptyString.isBlank());
   final String onlyLineSeparator = System.getProperty("line.separator");
   out.println("Line Separator Only -> " + onlyLineSeparator.isBlank());
   final String tabOnly = "\t";
   out.println("Tab Only -> " + tabOnly.isBlank());
   final String spacesOnly = "   ";
   out.println("Spaces Only -> " + spacesOnly.isBlank());
}

An example of executing this code is shown in the next screen snapshot.

Some of the methods whose code is shown above call "helper" methods that can be seen on GitHub.

The methods added to JDK 11's String are small additions, but will make certain "presentation" tasks related to Java Strings easier than in the past and reduce the need for third-party libraries.

Wednesday, June 27, 2018

Looking into Java's Future: Empty Value Types

Although the promising Java value types are not imminent, I still enjoy nosing around occasionally in the OpenJDK valhalla-dev mailing list to see how things appear to be progressing and to get an idea of what is to come. Admittedly, there are some discussions that are beyond my understanding given my limited exposure to the terms used and the low-level specifics of some of these messages. However, there are occasionally messages and threads that I understand well what is being written and find interesting. A recent example of this is the "Empty value type ?" thread.

Rémi Forax starts the thread by asking "Is empty value type targeted for LW1?" The example error message included with that question shows a LinkageError and ClassFormatError with the message "Value Types do not support zero instance size yet". The response to this question from Tobias Hartmann answers, "No, empty value types are not planned to be supported for LW1."

Before moving onto the rest of the thread [which is the part that interested me the most], I'll quickly discuss "LW1." In a message on that same OpenJDK mailing list called "[lworld] LW1 - 'Minimal LWorld'", David Simms states, "we are approaching something 'usable' in terms of 'minimal L World' (LW1)" and "we will be moving of prototyping to milestone stabilization." That same message states that the "label" is "lw1" and the affected-version and fixed-version are both "repo-valhalla". In other words, "LW1" is the label used to track bugs and issues related to work on the "minimal L world" implementation. You can reference John Rose's 19 November 2017 message "abandon all U-types, welcome to L-world (or, what I learned in Burlington)" for an introduction to the "L World" term and what it means in terms of value types.

Returning to the "Empty value type?" thread, Kirk Pepperdine asked a question that also occurred to me, "How can a value type be empty?" He added, "What is an empty integer? An empty string?" He said he was "just curious" and now I was too. Here is a summary of the informative responses:

  • Rémi Forax: "type [that] represents the absence of value like unit, void or bottom"
  • Rémi Forax: "type that represents the result of a throw"
  • Rémi Forax: "type that allows HashSet<E> to be defined as HashMap<E,Empty>"
    • Brian Goetz's message elaborates on the value of this: "Zero-length values can be quite useful, just not directly. Look at the current implementations of Set that delegate to HashMap; all that wasted space. When we have specialized generics, they can specialize to HashMap<T, empty>, and that space gets squeezed away to zero."
  • Rémi Forax: "transformative type like a marker type that separate arguments" (see message for example of this one)

I also liked the final (as of this writing) Kirk Pepperdine message on that thread where he summarizes, "Feels like a value type version of null."

Incidentally, there are some other interesting messages and threads in the June 2018 Archives of the valhalla-dev mailing list. Here are some of them:

I look forward to hopefully one day being able to apply value types in my everyday Java code. Until then, it is interesting to think of what might be and also to see how much work is going into making it so.