Three more Java Enhancement Proposals were proposed for targeting JDK 11 today. The three JEPs are JEP 181 ["http://openjdk.java.net/jeps/181"], JEP 315 ["JEP 315: Improve Aarch64 Intrinsics"], and JEP 333 ["JEP 333: ZGC: A Scalable Low-Latency Garbage Collector (Experimental)"]. The targeting of these three JEPs for JDK 11 was announced today on the OpenJDK jdk-dev mailing list in the respective posts "JEP proposed to target JDK 11: 181: Nest-Based Access Control", "JEP proposed to target JDK 11: 315: Improve Aarch64 Intrinsics", and "JEP proposed to target JDK 11: 333: ZGC: A Scalable Low-Latency Garbage Collector (Experimental)". Each JEP proposal is open for roughly one week and, if there are no objections, will be targeted officially to JDK 11 next week.
The purpose of JEP 181 is to "introduce nests" and the JEP's "Summary" states that "nests" are significant because they "allow classes that are logically part of the same code entity, but which are compiled to distinct class files, to access each other's private members without the need for compilers to insert accessibility-broadening bridge methods." A nice overview of JEP 181 can be found in the article "Java Nestmates Makes Progress," in which author Ben Evans describes this JEP as "a technical enhancement to the platform that pays off a 20 year old architectural debt introduced in Java 1.1."
The purpose of JEP 315, according to its "Summary," is to "improve the existing string and array intrinsics, and implement new intrinsics for the java.lang.Math sin, cos and log functions, on AArch64 processors."
The experimental JEP 333 introduces the "Z Garbage Collector," which the JEP's "Summary" section states is "also known as ZGC" and "is a scalable low-latency garbage collector." I like the "At a glance" sentence in the "Description" section that explains, "ZGC is a concurrent, single-generation, region-based, NUMA-aware, compacting collector. Stop-the-world phases are limited to root scanning, so GC pause times do not increase with the size of the heap or the live set." The JEP also explicitly states, "It is not a goal to provide working implementations for platforms other than Linux/x64." Important limitations of the initial version of ZGC are spelled out in the aptly named "Limitations" section which states, "The initial experimental version of ZGC will not have support for class unloading." Another limitation listed in that same section is, "ZGC will initially not have support for JVMCI (i.e. Graal)."
With today's announcements, there are now four JEPs waiting approval to be targeted for JDK 11. Besides the three covered in this post, JEP 330 had its review process for targeting JDK 11 extended to this week. Nine JEPs have already been targeted to JDK 11 as of this writing.
In the third chapter of his 2014 book "Java SE 8 for the Really Impatient: Programming with Lambdas," Cay Horstmann writes, "The point of all lambdas is deferred execution." He adds, "After all, if you wanted to execute some code right now, you'd do that, without wrapping it inside a lambda." Horstmann then lists several examples of the "many reasons for executing code later" and his last listed reason is "Running the code only when necessary." In this post, I look at some examples of this from the JDK that use Supplier to do exactly that: to execute a "code block" represented as a lambda expression "only when necessary."
In this post, I'll be focusing on JDK uses of Supplier, implying that the examples covered here are based on JDK-provided methods whose "target types" accept no arguments and supply a single result. These examples will only invoke the single get() method associated with the provided Supplier "when necessary." Note that all JDK uses of Supplier can be found in Supplier's Javadoc-generated HTML representation by clicking on the "Use" link.
A nice benefit achieved with Supplier-provided deferred execution (sometimes also called "lazy evaluation") is in deferring of an expensive operation for generating a log message until it is known that the result of that expensive operation will actually be logged. In other words, the expensive operation will only be invoked when it is known that it is necessary to do so because the result will be logged. I have blogged about this before in the posts "Java 8 Deferred Invocation with Java Util Logging" and "Better Performing Non-Logging Logger Calls in Log4j2."
Before the modern Java logging libraries and frameworks featured these Supplier-accepting APIs, the common way to avoid incurring expensive operations whose results would not be logged anyway was to use API-based "guard" statements, but these can clutter the code and reduce readability. There are now numerous resources on how to use Supplier-based logging framework APIs to ensure that an expensive operation that might potentially be logged is not actually executed until it is known to be necessary. These resources include my two just-mentioned posts on java.util.logging and Log4j 2 as well as "Writing clean logging code using Java 8 lambdas," "Lazy logging in Java 8," and "Log4j 2 and Lambda Expressions."
The JDK supports this Supplier-powered deferred execution for logging in both its java.lang.SystemLogger "log" methods and in numerous java.util.logging.Logger methods.
JDK 8 added two Supplier-powered methods to the Objects class that allow for an unwanted null (typically on a method parameter) to be detected and an appropriate response supplied only when determined that a null was indeed encountered. I wrote about one of these methods, Objects.requireNonNullElseGet, in my blog post "JDK 9: NotNullOrElse Methods Added to Objects Class." This method will only execute the provided Supplier by calling its get() method when it is determined that that first parameter passed to the method is indeed null. If the first parameter is not null, the Supplier is never executed.
The second Supplier-accepting method added to Objects with JDK 9 is requireNonNull​(T obj, Supplier<String>). This method allows a Supplier to supply a String to be used in a "customized NullPointerException" thrown when the first parameter is null. If the first parameter is not null, the Supplier's get() never needs to be invoked because an exception does not need to be thrown. A very similar method exists on the Objects class that accepts a String instead of a Supplier. This requireNonNull​(T, String) method may be preferable in some cases where the cost of the String generation is deemed less than the cost of generating the supplier. If, for example, the "custom string" is a string literal, it might be preferable to use the form that accepts that String directly instead of the one expecting a Supplier, especially if the null case is expected to be common.
The JDK examples of using Supplier to defer execution shown in this post were selected because of their relatively frequent use and because they are straightforward examples of how Supplier enables deferred execution or lazy evaluation in cases where no argument needs to be provided and one result needs to be supplied. Other uses of Supplier for deferred execution can be found in the java.util.concurrent concurrency package and in the JDK 8 streams-supporting java.util.streams package. Perhaps the best way to quickly identify the JDK's use of Supplier and its primitive-oriented counterparts is to look at the Javadoc-generated HTML representation of each classes "uses": Uses of Supplier, Uses of DoubleSupplier, Uses of IntSupplier, and Uses of LongSupplier. Interestingly, but not too surprisingly, there are no uses of BooleanSupplier.
The JDK-provided examples of using Supplier discussed in this post mostly demonstrate Horstmann's last listed possible reason for deferring code execution to a later point: "Running the code only when necessary." Other JDK examples of using Supplier demonstrate some of Horstmann's other listed reasons that one might want to "[execute] code later."
Although this post has focused on JDK use of Supplier to defer execution, its use is not limited to the JDK. As discussed earlier, Log4j 2 and other logging frameworks besides java.util.logging also provide Supplier-based logging APIs to allow deferral of construction of expensive strings for logging until it's known that the string will actually be logged. Similarly, one can use Suppliers in one's own code whenever the need arrives to specify code to be executed only when necessary and that code to be potentially exercised does not require an argument passed to it and will return (supply) a single result.
Although it was never a central goal of JEP 330 ["Launch Single-File Source-Code Programs"] to add support for the Unix-style shebang (#!), issues surrounding the potential ability of JEP 330 "single file source programs" to support a Unix-style shebang have generated significant discussion on the OpenJDK jdk-dev mailing list. This "vigorous discussion" has led to Mark Reinhold adding a week to the review period (now ends on May 31) for JEP 330 to allow for further discussion regarding targeting JEP 330 for JDK 11.
Although there are still some disagreements about whether shebang support should be added at all, it does seem that consensus is shifting to a proposal to explicitly differentiate between regular platform-independent Java source code files (those that end with extension .java) and the new JEP 330 "executable" platform-specific "single-file source-code programs". The explicit distinction is noteworthy because it would allow for shebang to be expressed in the latter (JEP 330 executable platform-specific single-file source-code programs) and not be used in the former (traditional Java platform-independent source code we're all accustomed to).
While renaming the file to a command-friendly name is optional, it is also expected to be common practice. For example, a source file named `HelloWorld.java` might be installed as `helloworld`. And, while the JEP describes use cases for executing a small single-file program with `java HelloWorld.java` or executing it as a platform-specific shebang script with just `helloworld`, it does not seem like there is a common use case to execute `HelloWorld.java`. So, if the shebang script is typically renamed to a command-friendly name, it will not be possible to compile it directly, with "javac helloworld", because that is not a valid command line for javac. This reduces any potential convenience of having javac ignore shebang lines.
The following table summarizes characteristics and advantages associated with each style of "Java" file.
/Names "Java source files (which end with a .java extension)" "executable scripts (which do not use [.java] extension.)"
"Java source files" "shebang scripts"
"Java source file" "script that contains Java code" or "platform-specific executable script"
"Java source files, as identified by a filename ending in '.java'"
Jonathan Gibbons summarizes the intent of JEP 330: "The general theme here is not to evolve Java into a scripting language, but to make tools like the Java launcher more friendly to supporting the use of Java source code in an executable text file, in order to reduce the ceremony of running simple programs."
The discussion has also covered alternative approaches such as binfmt_misc (see here also), Unix-style "here documents" (here documents defined), "support for '-' STDIN source in java launcher", and Linux being changed to support "la-la-bang: //!.
Another interesting side note from this discussion is Brian Goetz's "retrace" of how JEP 330 got to its current state. He talks about the "countless hours listening to people's concerns about Java" that led to this realization, "A general theme that people have expressed concern over is 'activation energy'; that doing simple things in Java requires too much fixed work." Goetz points out that JShell and JEP 330 are two of many possible ways of addressing this and that these two approaches were selected from among the many after making "subjective choices about which had the best impact" with consideration of "cost (in multiple dimensions) and benefit (or our subjective estimates of the benefits) when making these choices."
So, "regular Java" source code files will not be getting shebang support, but that is not a big deal as they don't really need them. It is looking likely, however, that JEP 330-based platform-dependent executable single-file scripts written in Java will support an optional shebang on the first line. We may know by Thursday of this week whether JEP 330 will be targeted for JDK 11.
JDK-8203630 ["Add instance method equivalents for String::format"] postulates that "the argument for implementing String::format as static appears to be that the format methods could be imported statically and thus conduct themselves comparably to C's sprintf." On a StackOverflow.com thread on the subject, Brandon Yarbrough writes, "by making the method static you can use format in a way that's very familiar and clean-looking to C programmers used to printf()." Yarbrough provides a code example and then concludes, "By using static imports, printfs look almost exactly like they do in C. Awesome!"
When I read in JDK-8203630 about this, I wondered to myself why I had not statically imported String.format when I've used it because it seems obvious to me now to do that. In this post, I look briefly at some personal theories I have considered to explain why I (and many others apparently) have not thought to statically import String.format consistently.
When static imports were introduced with J2SE 5, the new documentation on the feature presented the question, "So when should you use static import?" It answered its own question with an emphasized (I did NOT add the bold), "Very sparingly!" That paragraph then goes on to provide more details about appropriate and inappropriate uses of static imports and the negative consequences of overuse of static imports.
Although the original documentation warned emphatically about the overuse of static imports, their use did seem to increase gradually as developers became more used to them. In 2012, I asked, via blog post, "Are Static Imports Becoming Increasingly Accepted in Java?" I felt at that time that they were becoming increasingly accepted, especially when used in unit testing contexts and in more modern libraries and frameworks focusing on providing "fluent" APIs. Still, somehow, I did not think to consistently apply static imports to my uses of String.format.
I don't use String.format very often, so I thought that perhaps I just didn't get many opportunities to think about this. But, even in my relatively few uses of it, I don't recall ever importing it statically. As I've thought about this more, I've realized that the primary reason I probably don't think about statically importing String.format is the same reason that most developers have not thought about it: most of the popular and readily available online examples of how to use String.format do not use static imports!
When writing a blog or article covering a feature, especially if it's at an introductory level, it can be useful to NOT do things like import statically because the explicitly spelling out of the class name can improve the developer's ability to understand where the methods in the code come from. However, this also means that if a given developer reads numerous articles and posts and none of them show use of static imports, it is easy for that developer to use the API as shown in all those examples without thinking about the possibility of statically importing.
The following are some introductory posts regarding use of String.format. At the time of this writing, they do not demonstrate use of String.format via static import. I want to emphasize that this does not take away from the quality of these resources; if fact, some of them are excellent. This is instead intended as evidence explaining why String.format seems to be seldom statically imported in Java code.
The JDK 10 Javadoc for java.util.Formatter states "Like C's sprintf(3), Strings may be formatted using the static method String.format" and then provides a code sample using String.format instead of statically importing it.
Baeldung's detailed "Guide to java.util.Formatter" provides numerous code listings demonstrating use of String.format, but none of them are statically imported.
The detailed DZone post "Java String Format Examples" demonstrates use of String.format without static imports.
The "Java Code Geeks Examples" post "Java String format Example" ends with an example of using String.format without static import.
Recently published "Java String formatting with the String.format method (like 'sprintf')" provides useful discussion and examples, but does not discuss statically importing String.format.
GeeksForGeeks's "Java String format() with examples" provides multiple examples of String.format use, but none of them are statically imported.
"Java String Format Examples" provides multiple examples of applying String.format without using static imports.
"Java String format() method explained with examples" does not statically import String.format in its multiple examples.
The examples provided in the StackOverflow.com thread "How to format Strings in Java" do not statically import String.format.
"Java String format() method"'s multiple examples of String.format() do not statically import it.
Many of the examples in the above posts use String.format() to generate a String that is assigned to a local variable. In this context, the static import is arguably less valuable than when it is used to format a String within a greater line of code. For example, it is more "fluent" to statically import String.format() so that simply format() can be specified when that formatting takes place in a line of code doing other things beyond simply assigning the formatted string to a local variable.
Issues associated with static and instance methods sharing the same name in a class.
John Rose adds, "Refactoring static as non-static methods, or vice versa, is a very reasonable design move, but the language makes it hard to do this and retain backward compatibility."
Potential of StringConcatFactory for future faster Java string interpolation (see "String concatenation in Java 9 (part 1): Untangling invokeDynamic" for more details on StringConcatFactory).
Whether or not instance format methods come to Java's String, reading about JDK-8203444, JDK-8203630, and the associated mailing list discussion have provided me with some things to think about. If nothing else, I'll definitely be more apt to weigh String.format's performance when considering using it and will be more likely to statically import it when I do use it.
This past week, two Mark Reinhold messages (here and here) on the OpenJDK jdk-dev mailing list proposed two new JEPs for inclusion with JDK 11: JEP 329 ["ChaCha20 and Poly1305 Cryptographic Algorithms"] and JEP 330 ["Launch Single-File Source-Code Programs"]. I am excited about JEP 330, but that enthusiasm led me to blog on it when it was but a mere "draft" JEP (not even assigned to the 330 number at that point). The focus of the remainder of this post will therefore be on JEP 329.
The intent of JEP 329 is succinctly described in the JEP's "Summary" section: "Implement the ChaCha20 and ChaCha20-Poly1305 ciphers as specified in RFC 7539." That same "Summary" section also states, "ChaCha20 is a relatively new stream cipher that can replace the older, insecure RC4 stream cipher."
Disabled in Chrome 48 (and Chromium).
Deprecated with Firefox 36 and removed altogether with Firefox 44.
Disabled in Microsoft Edge and Internet Explorer 11 [KB3151631] for the stated reason that "there is consensus across the industry that the RC4 cipher is no longer cryptographically secure".
Turned off for Opera 12.
The only other widely adopted stream cipher, RC4, has long been deemed insecure. The industry consensus is that ChaCha20-Poly1305 is secure at this point in time, and it has seen fairly wide adoption across TLS implementations as well as in other cryptographic protocols. The JDK needs to be on par with other cryptographic toolkits and TLS implementations.
It is worth noting this important caveat mentioned in JEP 329's "Non-Goals" section: "TLS cipher suite support will not be part of this JEP. TLS support for these ciphers will be part of a follow-on enhancement." For additional details, see JDK-8140466 : ChaCha20 and Poly1305 Cipher Suites.
The "Dependencies" section of JEP 329 states that its only dependency is on the "constant-time math APIs" embodied in JEP 324 (see my previous post for additional overview details).
JDK-8198925 : ChaCha20 and ChaCha20-Poly1305 Cipher Implementations provides additional and even lower-level details than JEP 329. For example, it provides the specification of the new class javax.crypto.spec.ChaCha20ParameterSpec and its methods.
As of this writing, there are currently 8 JEPs targeted for JDK 11 and the 2 additional JEPs highlighted in this post's title are now proposed to target JDK 11, bringing the total number of JEPs targeted or likely to be targeted to JDK 11 to ten.
Joe Wang recently posted the message "RFR (JDK11/NIO) 8201276: (fs) Add methods to Files for reading/writing a string from/to a file" on the core-libs-dev mailing list. In this message, Wang provided links to the related bug (JDK-8201276), to the proposed specification (API) differences, and to the proposed code changes.
This is another case where a proposed change leads to some interesting discussion. The thread started with this message includes discussion regarding whether or not to include operating-system specific line separators Files.readString in methods implementations, discussion of alternatives of the readString methods such as simple Files.lines().collect(Collectors.joining("\n")), explanation of how raw string literals handle line separators, a described example of a common use case for these methods, and use of File.deleteOnExit() with unit tests.
JDK-8201276 shows that the proposed methods to implement "common operations" for "reading the content of a file into a string and writing a string text to a file" are currently planned for JDK 11.
It has been proposed that a method named isSameContents() be added to the Files class in JDK 11 via JDK-8202285 ["(fs) Add a method to Files for comparing file contents"]. Proposed by Joe Wang, this new method is "intended to be an extension to the existing isSameFile method since it stopped short of comparing the content to answer the query for whether two files are equal." JDK-8201276 also references this method and describes it as "a utility method that compares two files."
Proposing a new Files method isSameContent. Files currently has a method called isSameFile that answers the query on whether or not two files are the same file. Since two files containing the same contents may also be viewed as the same, it is desirable to add a method that further compares the contents, that would make the "is same file" query complete.
Explain the choice of isSameContent() to "stack it next to the existing isSameFile method since it's meant to be an extend to that method"
Point out that the String class has already chosen singular "content" over plural "contents"
States that one of the most common use cases of reading file content into a String is for "a quick read of small files" and references Files.readString().
A particularly insightful message in this thread is a Rémi Forax message providing code demonstrating how to use the JDK 9-added InputStream.transfer(OutputStream) method, the JDK 10-added local variable type inference, and classes MessageDigest and DigestOutputStream to hash the contents of a file in six lines of Java code.
It's looking increasingly likely that JDK 11 will provide several new useful "utility" methods in addition to the JEPs and other more significant features that will be coming with JDK 11.
Jim Laskey's recent message "RFR: CSR - JDK-8203428 Predicate::not" on the OpenJDK core-libs-dev mailing list calls out JDK Bug JDK-8203428 ["Predicate::not"]. The "Summary" of JDK-8203428 states, "Introduce a new static method Predicate::not which will allow developers to negate predicate lambdas trivially." It is currently assigned to JDK 11.
The requirement for predicate negation occurs frequently since predicates are defined antipodal to a positive selection; isNull, isEmpty, isBlank.
Presently there is no easy way to negate a predicate lambda without first wrapping in a Predicate Object.
There is a highly illustrative example of how this would work in the JDK-8203428 write-up. The "Problem" section of JDK-8203428 provides code that demonstrates how "predicate negation" would be performed today and the "Solution" section provides code demonstrating how the same functionality could be implemented with the proposed static method Predicate::not.
There are some other interesting messages in this mailing list thread. A Brian Goetz message in the thread states that "we did discover that default methods on [functional interfaces] combined with subtyping of [functional interfaces] caused trouble. But static methods are fine." A Rémi Forax message in the thread states that "stackoverflow has already decided that Predicate.not was the right method." A Sundararajan Athijegannathan message in the thread points out that "not(String::isEmpty) reads almost like !str.isEmpty()".
A message on a different thread on the core-libs-dev mailing list adds this additional context regarding the motivation behind the addition of Predicate.not(): "One of the rationals for adding 'Predicate.not' is to avoid adding another stream operation" because "we are trying to avoid adding 'overloaded' forms of the same kind of operation." This Paul Sandoz message provides the example that one would use the general filter(not(String::isEmpty)) rather than a specific Filter.reject or Filter.notFilter operation.
The addition of static function not(Predicate<T>) to Predicate is a small thing, but should improve the fluency of many lines of Java code.
The "primary goal" of JEP 324 is to provided "an API and an implementation for [the RFC 7748] standard," the two additional goals are also spelled out. One of the additional goals is to provide "a platform-independent, all-Java implementation with better performance than the existing ECC (native C) code at the same security strength."
JEP 327 ("Unicode 10") provides a straightforward "Summary": "Upgrade existing platform APIs to support version 10.0 of the Unicode Standard." The WikiBooks entry "Unicode/Versions" lists each major version of Unicode from Unicode 1.0 through Unicode 12.0. Unicode 10 was released last summary and Unicode 11 is planned for next month.
Joe Darcy recently requested review of the "webrev" (proposed code addition). This provides a peek at what the new @Serial might look like. The current proposal is for this annotation definition to reside in the java.io package, to be targeted at specific methods or fields, and to have SOURCE retention.
It appears likely that Java's String class will be gaining some new methods with JDK 11, expected to be released in September 2018.
JDK-8200425 String::lines lines() "String instance method that uses a specialized Spliterator to lazily provide lines from the source string."
stripLeading() "removal of Unicode white space from the beginning"
stripTrailing() "removal of Unicode white space from the ... end"
JDK-8200437 String::isBlank isBlank() "instance method that returns true if the string is empty or contains only white space"
The current JavaDoc for String::trim does not make it clear which definition of "space" is being used in the code. With additional trimming methods coming in the near future that use a different definition of space, clarification is imperative. String::trim uses the definition of space as any codepoint that is less than or equal to the space character codepoint (\u0040.) Newer trimming methods will use the definition of (white) space as any codepoint that returns true when passed to the Character::isWhitespace predicate.
The set of characters from U+0000 to U+FFFF is sometimes referred to as the Basic Multilingual Plane (BMP). Characters whose code points are greater than U+FFFF are called supplementary characters. The Java platform uses the UTF-16 representation in char arrays and in the String and StringBuffer classes. In this representation, supplementary characters are represented as a pair of char values ... A char value, therefore, represents Basic Multilingual Plane (BMP) code points, including the surrogate code points, or code units of the UTF-16 encoding. An int value represents all Unicode code points, including supplementary code points. ... The methods that only accept a char value cannot support supplementary characters. ... The methods that accept an int value support all Unicode characters, including supplementary characters.
I added the bold emphasis in the above quote to emphasize the significance of a "code point," which is defined for the Java context as "a value that can be used in a coded character set". Four of the five proposed new methods for String in JDK 11 rely heavily on the concept embodied in Character.isWhitespace(int) to determine how to "trim" a given string or when determining if a given string is "blank."
Speaking of Unicode, JEP 327 ["Unicode 10"] has been proposed to be added to JDK 11 as well. As that JEP states, its intent is to "upgrade existing platform APIs to support version 10.0 of the Unicode Standard."
The new methods on String currently proposed for JDK 11 provide a more consistent approach to handling white space in strings that can better handle internationalization, provide methods for trimming whitespace only at the beginning of the string or at the end of the string, and provide a method especially intended for coming raw string literals.