It’s now over two years since the release of JDK 9 and, with it, the switch to a time-based rather than feature-based release schedule. It seems incredible that it took very nearly eleven years to get from JDK 6 to JDK 9, yet in just over two years we’ve gone from JDK 9 to JDK 13.

Each release under this new strategy provides a smaller set of features than we had in the old major release approach. What we’re seeing, though, is the overall rate of change is faster than it’s ever been, which is a significant advantage for keeping Java vibrant and attractive to developers.

One of the things that is now possible with a fast release cadence is the ability to add features without casting them in stone by making them part of the Java SE standard. In JDK 9, the introduction of the module system provided incubator modules. Quoting the summary directly from JEP 11, where they are defined:

“Incubator modules are a means of putting non-final APIs and non-final tools in the hands of developers, while the APIs/tools progress towards either finalization or removal in a future release.”

API development is a tricky business and exponentially so when you’re dealing with the most popular programming platform on the planet. Ken Thompson, one of the original developers of UNIX, was once asked what he would do differently if he were redesigning the UNIX system. His reply was “I’d spell creat with an e.” Because of Ken’s choice in the late 1960s, we forever have to misspell create when using that system call. The first incubator module was for the HTTP/2 protocol support. If you read through JEP 321, which brought this API into the standard, there were several changes between the initial and final API.

APIs, in some ways, are easier to introduce then change because the package namespace can be changed relatively easily. In the case of HTTP/2, the incubator package was jdk.incubator.http and this was migrated to jdk.net.http in JDK11.

Language and VM features are a harder thing to introduce without making them part of the standard, but that is what we now have with Preview Features. Again, quoting from JEP 12, where they are defined:

“A preview language or VM feature is a new feature of the Java SE Platform that is fully specified, fully implemented, and yet impermanent. It is available in a JDK feature release to provoke developer feedback based on real world use; this may lead to it becoming permanent in a future Java SE Platform.”

An important distinction to make here is that these are not beta features in the normal sense. As the JEP says, these are complete features, just not permanent.

The first Preview Feature was included in JDK 12 in the form of Switch Expressions (defined in JEP 325). This is a great feature that allows us to significantly reduce the boilerplate code associated with a switch statement and reducing potential bugs. This is achieved by eliminating the need for an explicit break in each block of case statements and allowing a single assignment of the return value, eliminating the need to remember to do this in each block of case statements.

As a preview feature, this is not included by default (since it’s not part of the standard). Additional command-line flags must be used for both compilation and with the Java runtime to make it clear that you want to use this feature (–enable-preview).

The switch expression is an excellent example of the benefit of this concept. In the initial implementation, the new and old switch syntax could be combined in something like this:

int a = switch(b) { case 1: break 5; case 2: break 9; default: break 0; }

break is used here with a numeric value, which is what will be returned from the switch expression. A break can also be used with a label but, since a label cannot be a number (or start with a number), the syntax does not cause a problem. However, feedback led to a decision to drop the use of break and replace it with yield to make it clearer (see JEP 354).

In JDK 13, JEP 355 (Text Blocks) was included, which was another preview feature. Aside from the technical details, this feature was interesting because it also included API changes. Three methods were added to the String class (stripIndent, translateEscapes and formatted). Because these are part of an existing class, an incubator module can’t be used (it would also be excessive for three methods). As a result, these three methods were immediately deprecated so that they could be removed in a subsequent release.

The trend of incubator modules and preview features is continuing, and JDK 14 will have no less than five of them, as well as switch expressions becoming standard:

Looking at the history of Java, it’s easy to wish that we’d had these capabilities right from the very beginning (several features and APIs that could have benefitted from changes based on feedback). However, with multi-year release development cycles, this is not practical. Moving to the twice-yearly JDK release has not just provided more features more quickly but allowed the OpenJDK developers to deliver features in the form that is most useful for developers.

Let’s see what incubator modules and preview features we get in the future.