Java 11 – New Features, Code Examples & Support

Java 11Java 11 was officially released by Oracle on 25th Sept 2018. This blog post highlights the subset of features in this next major release of Java that will be of most interest to enterprise Java developers. These include  a small number of new language features, for which I have also provided some code examples showcasing how they can be used. This post also outlines the significance of this new Java release from a support & maintenance perspective; upgrade considerations; and includes a reminder about the recent change in the licensing terms for the Oracle JDK.

1) A new Long Term Support Release

Java 11 is the second major release to be created under Oracle’s relatively new, fixed-time based release cycle for Java – which favours regular, small releases over the past fixed-scope releases that often suffered major delays. Coming six months after the Java 10 release (March 2018), Java 11 is evidence that Oracle are so far sticking to their new release schedule.

More significantly, Java 11 has been designated a Long Term Support (LTS) release by Oracle. (In this respect it joins Java 8, which is the only other previous LTS release). Being an LTS release, Oracle commit to offering paid support & maintenance for this release of Java for a minimum of 5 years (to Sept 2023), with all other support vendors following suit. In addition, when Oracle call time on providing free bug fixes & security patches for the release, six months after its release (March 2019), this new LTS release will be handed over to and continue to be maintained by other OpenJDK committers who will ensure that bug fixes & patches that Oracle make to future releases (Java 12 onwards) will be backported into Java 11,ensuring its quality & security continue are improved. In contrast, the previous Java 10 release, which is a non-LTS release, will now cease to benefit from any further bug fixes or security patches, and Oracle (and most other vendors) will no longer offer any support (paid or otherwise) or maintenance for it. Java 10 is, as of now, end-of-life.

For those Java users (including myself) who, for good reason, have decided to adopt a policy of only upgrading their production Java applications to LTS releases, Java 11 is a significant new release. It is our first chance to upgrade  our apps in production from Java 8. In the first instance this will deliver all of the JDK performance improvements that are contained in intermediate (9 and 10) releases. In addition, once Java 11 has proven itself in our production environments we can also subsequently enable and start to utilise the new language features (e.g. static factory methods for Collections; private methods in interfaces; Streams API enhancements; var etc) contained in those previous releases in our production code.

2) New Language Features

Java 11 delivers a small no. of new language features of note, and a few useful enhancements to the standard library  APIs, that will be of interest and value to developers. The main ones, described in more detail below, include –

  • The finalised version of a new, modern HTTP (and WebSocket) client
  • Local Variable (var) syntax for Lambda parameters
  • Streamline launching (compiling & running) single file Java programs
  • Additional String utility methods, etc.

2.1) New HTTP (and WebSocket) Client

Java 11 includes a new, modern HTTP client. (This had previously been available as an ‘incubator’ module since Java 9, but it has now graduated following the finalisation of its API). The client is contained in the java.net.http module/package and consists of the following major classes and interfaces:

  • HttpClient – The entry point for using the API.
  • HttpRequest – A request to be sent via the HttpClient.
  • HttpResponse – The result of an HttpRequest call.
  • WebSocket – The entry point for setting up a WebSocket client.

The client is a significant improvement over Java’s existing HTTP client support –  java.net.HttpURLConnection – which due to numerous limitations wasn’t a viable option for production usage. The improvements include

  • Simpler API and Better Code Readability – A fluent API makes constructing requests and processing responses simpler to code, easier to read and less verbose. Use of the Builder pattern instead of setter methods also increases thread-safety of the client and its requests/responses.
  • Compatible with other modern Java APIs – The client supports using modern Java (8+) language features and APIs including Lambda expressions;  Optional; and the standard (java.time) Date and Time API, etc.
  • Support for Non-blocking I/O – The client supports executing requests without blocking the current thread via the use of an async API/callbacks, which utilise java.util.concurrent.CompletableFuture
  • Protocol support – In addition to HTTP/1.1, the new HTTP client also provides support for HTTP/2 (the default, with automatic negotiation and fallback to HTTP/1.1) as well as WebSocket.

The new HTTP client should provide a viable alternative to using third-party libraries such as Apache HttpComponents, as has been necessary in the past. Although this will depend on how well it proves to support more advanced features such as connection pooling, timeouts, etc. We’ll also need to wait for it to be supported by higher-level libraries such as REST clients (e.g. Spring’s RestTemplate or WebClient).

For some introductory examples of how to use the new HTTP client see the java11-examples project, specifically class HttpClientTest.

2.2) Local Variable (var) syntax for Lambda parameters

The previous release of Java (10) introduced type inference for local variables declared using ‘var’, e.g.

final var countryToCityMap = Map.of(         
  "UK", List.of("London", "Manchester", "Birmingham", "Liverpool"),
  "Italy", List.of("Rome", "Turin", "Naples", "Milan")         
);

For more details of this feature see my earlier post Java 10 – New Features, Code Examples & Support – section 1.1) Local variable type inference (‘var’).

Java 11 extends LVTI support to allow ‘var’ to also be used on parameters of Lambda expressions. Lambda expressions already supported type inference for params since they were introduced in Java 8, as shown below  –

    final List<String> list1 = new ArrayList<>(“the”, ”quick”, “brown”, “fox”);
    Collections.sort(list1, (s1, s2) -> s1.length() - s2.length());

You might therefore wonder why this feature was added in Java 11. The reason is that it allows Lambda parameters to be annotated without having to specify an explicit type (sacrificing type inference), e.g.

List<String> strings = inputStrings.stream()
 .map((@NonNull var s) -> s.toLowerCase())
 .collect(Collectors.toList())

2.3) Streamline launching single file Java programs

To date launching a Java program from the command line has been a two step process. Before you could run a program using the ‘java’ command you first needed to compile it using ‘javac’. Java 11 streamlines the process by allowing you to launch (both compile and run) a Java program implemented in a single source file using the ‘java’ command alone.

For example, given a Java source file ~/src/test/java/com/neiljbrown/java11/HelloWorld.java containing the following code –

package com.neiljbrown.java11;

public class HelloWorld {
  public static void main(String[] args) {
    String greeting = "Hello " + (args.length > 0 ? args[0] : "World!");
    System.out.println(greeting);
  }
}

Using a Java 11 JDK you can launch (compile and run) the program using the following single command –

$ java -classpath ~/src/test/java  com/neiljbrown/java11/HelloWorld.java Duke!!

resulting in the following output

Hello Duke!!

This feature is mostly designed to make Java easier to learn for beginners (in a similar way to JShell), but it also reduces the ceremony for running simple utility programs written in Java, making it closer to running a script. In this regard, there is also support for executing Java source code from a script using the ‘shebang’ support provided by *nix O/S. For example –

$ cat > hello-world.sh
#!/Users/neilbrown/.sdkman/candidates/java/11.0.2-open/bin/java --source 11
public class HelloWorld {
 public static void main(String[] args) {
    String greeting = "Hello " + (args.length > 0 ? args[0] : "World!");
    System.out.println(greeting);
 }
}
<CTRL-D>
$ chmod +x hello-world.sh
$ ./hello-world.sh Duke

(Note, when using shebang support as above, the file can have any extension, including none, except “.java”).  For more details of the feature see JEP 330: Launch Single-File Source-Code Programs.

2.4) Enhancements to the Standard Library APIs

A few minor enhancements have been made to the Java SE library APIs in JDK 11. Those that will be of most use in everyday development are outlined below.

2.4.1) java.lang.String

The java.lang.String API has been extended to add several useful methods for performing commonly required operations on strings, which will reduce (although is still a long way from  eliminating) the need to use thirdparty library support. The new methods include, e.g.

  • isBlank() : boolean – Checks whether the string is blank – is empty (as indicated by existing isEmpty() method) or also contains only whitespace characters.
  • strip() : String – Removes leading and trailing whitespace from the string. Differs (and generally serves as a replacement) for the existing trim() method in respect to what characters are classified as whitespace – this new method includes Unicode whitespace characters. There are also two new variants of this method – stripLeading() and stripTrailing() – which as their names suggest only strip whitespace from the beginning (so-called indentation whitespace) or end of the string, rather than both.
  • repeat(int) : String  – Concatenates the string a specified number of times and returns it. Provides an better performing alternative to doing the same using StringBuilder.append(String) in a loop.
  • lines() : Stream – Supports processing a multi-line string. Returns a java.util.stream.Stream of lines split by a small no. of different line terminators (e.g. CR, LF and CR/LF), plus the end of string.

For an example of these new methods in action, see the class StringTest in the java11-examples project.

2.4.2) java.util.function.Predicate

The Predicate class has only be extended with a single method, but it’s a handy one.

A new static method Predicate.not(Predicate) supports creating a Predicate that is the negation of a supplied Predicate. This is useful, as it supports using a method reference when the right hand-side/body of a Lambda expression is a negated method invocation (on the single Lambda  param), which wasn’t previously possible, e.g.

List<String> filteredLyrics = lyrics.lines()
 .filter(Predicate.not(String::isBlank))
 .collect(Collectors.toList());

See the full code in class PredicateTest in the java11-examples project.

2.4.3) java.nio.file.Files

A couple of overloaded utility methods have been added to java.nio.file.Files which make it simpler/more convenient to read and write a string to and from  a file, using an optional (default UTF-8) character set/encoding. See –

  • readString(Path) : String  / readString(Path, Charset) : String – Reads the contents of a file into a string, decoding from bytes to characters using UTF-8 or an optional alternative char set.
  • writeString(Path, CharSequence, java.nio.file. OpenOption[]) : Path / writeString(…,java.nio.file. Charset,…): Path – Writes a CharSequence (e.g. String, StringBuffer, etc) to a file, encoding characters are encoded into bytes using UTF-8,  or the alternative specified char set.

2.4.4) java.util.regex.Pattern

The existing util.regex.Pattern class represents a compiled regular expression, that can subsequently be used to efficiently match supplied Strings (via its matcher(String) method. In JDK 11, a new instance method has been added to the class, which makes it easier to check (e.g. filter) whether a Stream of Strings matches a regular expression. For more details see method asMatchPredicate():  Predicate<String>.

3) Other Features of Interest to Developers

3.1) Profiling JVM Apps – Addition of Flight Recorder

Flight Recorder is an existing low-overhead profiling tool (set of APIs etc) designed and built by Oracle engineers to support troubleshooting, monitoring and profiling the JVM and apps, whilst running in production, with minimal overhead. Prior to JDK 11, the tool was only available as a paid feature in the Oracle JDK. In JDK 11, Oracle have contributed Flight Recorder to the open source OpenJDK project, as part of their ongoing process to migrate the Oracle JDK to use/share the OpenJDK project source code, and remove any  proprietary features. As a result, Flight Recorder is now free to use in JDK 11. The relevant APIs and Java classes are packaged in two new JDK modules – jdk.jfr and jdk.management.jfr. For more details see JEP 328: Flight Recorder.

3.2) Security – TLS 1.3 Support

The Java Secure Socket Extension (JSSE) in the JDK provides a Java implementation of the SSL, TLS, and DTLS protocols. Prior to JDK 11, the JSSE API and JDK implementation supported SSL 3.0, TLS 1.0, TLS 1.1, TLS 1.2, DTLS 1.0 and DTLS 1.2.

TLS 1.3 (RFC 8446) is a new, major overhaul of the TLS protocol which supersedes, obsoletes and provides significant security and performance improvements over TLS 1.2. Several early implementations from other vendors have already  become available, and are starting to be used. JDK 11 has been enhanced to support the essential parts of TLS 1.3, in order to remain a competitive/relevant stack from a web security perspective and ensure continued compatibility, although this does not yet extend to Datagram Transport Layer Security (DTLS).

For more details see OpenJDK JEP http://openjdk.java.net/jeps/332

In addition to the above, as is usual, this major new release of the JDK also includes hundreds of smaller enhancements and countless bug fixes, as well as performance improvements.

4) Upgrade Considerations

When planning your upgrade to JDK 11, consider the following issues.

4.1) Third Party Software Compatibilty /  Support

Before committing to a date for upgrading your apps to JDK 11 in production, first  check if / when the providers of all your dev tools and third party dependencies have confirmed their software is compatible. The faster (six-monthly) pace with which new versions of Java are now being produced by Oracle creates more work for third party developers of Java tools (build, IDE, static code analysis), frameworks (e.g. Spring) and libraries (e.g. Jackson). This will inevitably lead to there being a lag before these projects have had time to test their software for compatibility and release new versions containing any necessary updates. If you stick to using popular, mainstream tools and dependencies, then you shouldn’t have to wait too long. For example –

Toolchain

IDE – JetBrains were ahead of the curve with IntelliJ having added IDE editor compilation support for Java 11 whilst it was still Early Access (see Java 11 in IntelliJ IDEA 2018.2; 22/06/18).

Build Tools – [Update  11/2018] Support for running Gradle using  / from JDK 11 was added a couple of months after JDK 11 was (GA) released, in Gradle 5.0, released 11/2018. See Gradle 5.0 Release Notes  > Java 11 Runtime Support.

Application Frameworks

Spring Framework – The Spring framework also confirmed and announced compatibility with Java 11, shortly after it was released in Sept, based on work  they had been doing in parallel using JDK early access releases. However, notably JDK 11 is only supported by Spring 5.1 or greater, so you may have to plan a Spring upgrade prior to upgrading to Java 11. Spring 5.1 continues to  support Java 8+ also to make your life easier. For more the latest official statement of Spring’s supported JDK versions see Spring Framework Versions  > JDK Version Range.

4.2) Removal of JEE Modules

When Java was modularised back in Java 9, a number of the newly created modules were immediately marked as deprecated and scheduled for removal from a future release of the JDK. These included –

  1. Module java.activation – JavaBeans Activation Framework (JAF)
  2. Module java.corba – CORBA – a legacy technology for building distributed systems based on object serialistion and remote invocation, that has been largely superseded by more modern data serialisation solutions such as JSON over HTTP.
  3. Module java.se.ee – Aggregator module for the previous  6 modules.
  4. Module java.transaction – Java Transaction API (JTA).
  5. Module java.xml.bind –  Java API for XML binding (JAXB)
  6. Module java.xml.ws – Java API for XML web services (JAX-WS) and related APIs (SAAJ and web services metadata)
  7. Module java.xml.ws.annotations – Common Annotations.
  8. Module jdk.xml.ws – Tools for JAX-WS
  9. Module jdk.xml.bind – Tools for JAXB.

The java.corba module contained code for legacy technology which is now rarely used, and was therefore ‘dead-weight’ in the JDK for most people. The other modules provided implementations of a subset of JEE platform APIs in JSE, with the original goal of making it easier for developers to build SOAP and XML web services. They were deprecated as their inclusion in the JSE (since Java 6) had a number of ongoing drawbacks (e.g. JDK maintenance overhead and bloat; problems of unwanted dependencies between JSE and JEE; the JSE provided versions become out of date and conflicting with versions added to classpath). (For more details of  these deprecations see Java SE 9 ( JSR 379) Final Release Specification > 10 APIs proposed for removal).

All the above modules have now been removed from the JDK in Java 11. The removal of the CORBA module is very unlikely to affect most Java shops, however some of your apps (especially the older ones) may well consume or provide SOAP or XML based web services and depend on one of the removed JEE modules for their implementation.

Whilst these modules have been removed from the JDK, they continue to be developed by  the JEE community, and releases are available from public binary repos, such as Maven Central. The solution is therefore to add the extra external JARs containing the JEE APIs and their implementations to your app’s declared compile or runtime dependencies. If this  entails upgrading your version of the JEE APIs, it may well be best done prior to upgrading to Java 11.

For more details of these changes in Java 11 see JEP 320: Remove the Java EE and CORBA Modules.

5) Oracle JDK Distribution – Licensing, Maintenance & Security

If you’re currently using the “Oracle JDK” binary distribution of Java 8, then you should already know by now about the well publicised changes to the licensing of that JDK from Java 11 onwards. (If not see my previous  post on the subject – Oracle’s Recent Changes to Java (JDK) – Overview, Impact & Advice),

In addition, Oracle will produce the final free update to the Oracle JDK for business users in January  2019. After that time, if you remain on Oracle JDK 8, whilst it continues to be free to use in production, you’ll only be able to obtain future security updates (and any fixes) if you have a commercial license (JSE subscription) with Oracle. If security is important to you (or maybe essential for compliance), then you have two choices. You can stick with the Oracle JDK and purchase the monthly subscription from Oracle. Alternatively,  switch to a free OpenJDK distribution produced by another vendor and continue to benefit from the free updates that will be made to the OpenJDK code base. If you decide to adopt the latter option, then from a planning perspective, changing your  OpenJDK distribution and upgrading from Java 8 to 11  at the same time, may make sense, as for the latter you need to upgrade the JDK and regression test anyway.

6) Summary

In this post we covered

  • The significance of Java 11 being a Long Term Support (LTS) release, and therefore strategically being a good release to target, e.g. if upgrading from Java 8.
  • The small no. of new language features in Java 11 that will be of most interest to developers, including the new HTTP client (with WebSocket API support), local variable type inference syntax (var) for Lambda params; and streamline launching of  single file Java program. We also covered some of the most useful enhancements to the JSE APIs in Java 11, such as new String handling methods, and convenience methods for reading/writing Strings to/from files.
  • A couple of other features, beyond Java language enhancements, of interest to developers, such as the Flight Recorder production profiling tool now being available for free, and from a security perspective Java 11 also includes support for the latest version (1.3)  of the TLS standard.
  • Things to consider and check prior to finalising your Java 11 upgrade plans, most notably the timeline for third-party providers of the libs and tools you depend upon having tested compatibility of their software with Java 11 and whether this requires you upgrade that software ahead of time. Also, if you’re producing or consuming SOAP/XML web-services, then you may also need to update your build dependencies.
  • And, if you’re still using the Oracle JDK distribution of Java 8, don’t have or plan to purchase an Oracle subscription, but still want to continue to benefit from security updates post Jan 2019, then upgrading from Java 8 to Java 11 may also be a good /  opportune time to switch to a different OpenJDK distribution.

I hope you found this post useful. Remember, that you can find code examples for all the new language features and API enhancements mentioned above, online in my java11-examples project.

Thanks.

Leave a comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s