JDK 16 was finalized as a release candidate on February 18, 2021, and officially released on March 16, 2021. Like JDK 15, JDK 16 will be a short-term release with only six months of support. JDK 17, scheduled for September 2021, will be a long term support (LTS) release with several years of support. Although JDK 16 is a short-term release, and most enterprises and projects are still stuck with JDK 11, released in September 2018 (and even earlier, JDK 8, released in March 2014), javaers are looking forward to new versions of the JDK and continue to learn about them. In this article, we will play JDK 16 with you.

New features

Before we get started, let’s take a look at 17 new features that come with JDK version 16.

This article explains the new features

357: OpenJDK source repository is migrated from Mercurial to Git. Pushing for this change will have advantages in terms of versioning system metadata size, available tools, and hosting.

369: Migration to GitHub, this change is based on the migration of the OpenJDK source repository to Git, the JDK 16 source repository will appear on the most popular social networking sites for programmers.

386: Porting the JDK on the X64 and AArch64 architectures to Alpine Linux and other Linux distributions that use MUSL as their primary C library. Musl is a Linux implementation of the standard library features described in the ISO C and Posix standards. Alpine Linux is widely used in cloud deployments, microservices, and container environments due to its small image size. The Docker container image for Linux is smaller than 6MB. Let Java run out of the box in such Settings, and allow Tomcat, Jetty, Spring, and other popular frameworks to work in these environments. By using JLink to reduce the size of the Java runtime, users can create a smaller image to run a specific application.

394: Pattern matching for the instanceof operator, previewed in JDK 14 and JDK 15, will be finalized in JDK 16. Pattern matching allows general logic in a program (that is, conditional extraction of components from objects) to be expressed more concisely and safely.

395: Provides the Record class as a transparent carrier of immutable data.

Other new features

347: enable C++ 14 language features that allow the use of C++ 14 features in JDK C++ source code and provide specific guidance on what features can be used in HotSpot code.

376: Moves ZGC (Extensible low-latency Garbage Collector) thread stack processing from the safe point to the concurrent phase. The ZGC garbage collector is designed to make GC pauses and scalability issues in HotSpot a thing of the past.

380: Added UNIX-Domain Socket Channels, where UNIX-Domain (AF_UNIX) Socket support was added to the Socket Channel and Server Socket Channel APIS in the Nio. Channels package.

387: Elastic Metaspace functionality returns unused HotSpot virtual machine Class Metadata(Metaspace) memory to the operating system more quickly, reducing Metaspace footprint and simplifying Metaspace code to reduce maintenance costs.

388: Porting JDK to Windows/AArch64 platform.

389: Incubation-stage external linker API that supports statically typed, pure Java access to native code. The goal of this initiative is to provide interaction with the C language by replacing JNI (Java Native Interface) with a more advanced pure Java development pattern. Its performance will be superior to THAT of JNI.

390: Warning advice for Value-based Classes: Specify the original wrapper class as value-based, discard its constructor for removal, and prompt for a new deprecation warning. False attempts to synchronize any instance of a value-based class in the Java platform are warned.

392: Provides the JPackage tool for packaging standalone Java applications.

396: JDK internals are strongly encapsulated by default, with the exception of key internals such as misc.unsafe. The goals of this initiative include improving the security and maintainability of the JDK and encouraging a gradual migration from direct use of internal elements to use standard apis, so that both developers and end users can easily upgrade to future versions of Java.

397: Previously previewed in JDK 15, the second previewed sealed classes and interfaces in JDK 16 limit the classes and interfaces that can be extended or implemented. The goals of this initiative include allowing the creator of a class or interface to control the code responsible for implementing it, providing more declarative ways to restrict the use of superclasses than access modifiers, and supporting the future evolution of pattern matching by providing a foundation for pattern analysis.

338: Vector API for the incubation phase (the JDK will be equipped with an incubator module), JDK.incubator. Vector to express vector computations compiled to best hardware instructions on supported CPU architectures to achieve better performance than equivalent scalar computations.

393: Incubation-phase external memory access API that allows Java programs to securely access external storage (including local, persistent, and managed heap storage) outside the Java heap.

See the JDK Enhancement Process identifier (see resources at the end of this article)

Immediately reveal,

After reviewing the 17 new features, I couldn’t wait to try JDK 16 and some of the engineering benefits. Download JDK 16 candidate from jdk.java.net/16/.

To easily switch between JDK versions on your system, use jenv (github.com/jenv/jenv).

We add the downloaded JDK16 path to Jenv and use it after making the following Settings.

jenv add ${JDK16_Path}
jenv global openjdk64-16
Copy the code

If all goes well, when you view the JDK version, you will get something like the following.

java -version
openjdk version "16" 2021-03-16
OpenJDK Runtime Environment (build 16+36-2231)
OpenJDK 64-Bit Server VM (build 16+36-2231, mixed mode, sharing)
Copy the code

If you are using earlier versions of IDEA as a development tool, you may receive the following error when running your application using JDK 16:

Cannot determine path to 'tools.jar' library for 16 (path/to/jdk-16) when running from IDEA, you should update to the latest version.
Copy the code

This is due to JDK9 refactoring of the Java runtime, removing rt.jar, tools.jar, dt.jar, and various other internal JAR packages. Earlier development tools usually rely on such JAR packages, which can be resolved by upgrading IDEA. Go to the official website to obtain an IDEA 2021.1 EAP pre-release version (www.jetbrains.com/zh-cn/idea/…

New Feature Interpretation

The migration to making

As early as September 2020, OpenJDK used the JDK repository on Github as the primary read/write repository for JDK 16 source code. With the release of JDK 16, this will be the first version of the OpenJDK developed on Github.

There are three main reasons for moving the OpenJDK source repository from Mercurial to Git: version control system metadata, available tools, and the size of the hosting available.

In terms of versioning metadata size, the initial prototype of the converted repository has shown a significant reduction in the size of the published control metadata. For example, the.git directory in the JDK repository using Git is about 300MB, while the.hg directory using Mercurial is about 1.2GB. Reducing metadata saves local disk space, reduces clone time, and reduces data transfer.

Git has more tools available than Mercurial. All text editors can integrate Git either locally or through plug-ins. In addition, almost all ides come with Git integration, including Eclipse, Visual Studio, and IDEA.

On the available hosting side, there are many options for hosting Git repositories, either self-hosted or as a service. Reasons for using external source hosting providers include performance, access control of Web apis that interact with developers, and a thriving community.

After migrating OpenJDK to Github, there are several advantages for Java developers: fork a JDK 16 repository (github.com/openjdk/jdk…

If the Internet speed is fast enough, read the code online through Github’s tool Github1s (github.com/conwnet/git… 16 source code (github1s.com/openjdk/jdk…

Clone JDK 16 source code if you are working under IDEA.

Open Project Structure (command+;) , set the Project SDK to JDK 16 and set the Project language level to 16.

Then you can enjoy reading the JDK 16 source code.

Port the JDK to Alpine Linux

In the cloud native era, I understand that improving efficiency is the first principle: smaller mirror volumes are distributed more quickly

Start the application/container quickly

This ensures that the system scales horizontally fast and can be rolled back quickly if problems occur.

In addition, to reduce costs, a smaller image size takes up less memory and consumes less resources to distribute.

Alpine Linux is a standalone, non-commercial, general-purpose Linux distribution that aligns with the efficiency principles of cloud native.

It focuses on security, simplicity, and resource efficiency and is built around Musl Libc and BusyBox. This makes it smaller than traditional GNU/Linux distributions.

Porting the JDK to Alpine Linux will allow Tomcat, Jetty, Spring, and other popular frameworks to work in it. Users can create a smaller image to launch and run specific applications.

With Docker ready in advance, let’s build a Alpine Linux image, add JDK 16, and finally run a simple Spring Boot program to demonstrate.

Build the Alpine Linux image

Docker run Alpine echo 'Hello Alpine! 'Copy the code

A look at the image size using the Docker images command shows Alpine’s image size at the end of this article is just 5.6MB. Compared to debian, Ubuntu, centos and other systems that use dozens or even hundreds of MB of images, Alpine is really small!

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
alpine              latest              7731472c3f2a        7 weeks ago         5.61MB
Copy the code

Add the JDK 16

OpenJDK reduces the size of the Java runtime by using Jlink (JEP 282), which can be obtained from DockerHub: 16-JDK-alpine. Or the following Docker command:

docker pull openjdk:16-jdk-alpine
Copy the code

Running Spring Boot

Spring Boot FatJar: Hello World! IO /guides/gs/r… Create a Dockerfile using openJDK: 16-JDK-alpine and add the Spring Boot program.

FROM openjdk:16-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
Copy the code

Build and run

# build mirror, Set JAR_FILE to the Jar package path of the Spring Boot program docker build --build-arg JAR_FILE=target/rest-service-0.0.1- snapshot.jar -t Alpine-jdk16-app :latest. # Check docker images # Check docker images # 8080 docker run -d -p 8080:8080 alpine-jdk16-app:latest # Check docker ps # check docker stop ${CONTAINER_ID} # access application curl - w '\ n' http://127.0.0.1:8080/greeting? name=jdk16Copy the code

At this point, Spring Boot with the JDK 16 runtime from the Alpine Linux system is up and accessible.

The size of the Alpine JDK 16 image is about 321MB. This is 30% less than the 467MB of Oracle’s official Linux version.

Record the class

A preview feature for the Record class has been available since JDK 14 and will be a permanent feature in JDK 16. The Record class is a transparent vehicle for immutable data, a response to complaints that Java is too verbose. The goals of this initiative include designing an object-oriented constructor that represents a simple set of values, helping developers focus on modeling immutable data rather than extending behavior, and automating data-driven methods (such as equals() and accessors for attributes).

This type can be created with newer versions of IDEA:

After declaring the Record class, there is little additional code to add, and a set of implicit declarations makes the code simple to write:

Attributes are implicitly declared

The constructor is implicitly declared

Implicitly declare equals(), hashCode(), toString()

Accessors are implicitly declared for a property with the same name as the property

public record Point(int x, int y) {}
Copy the code

The Record class supports Local Classes, so when you need to use the Record temporarily, you can easily define and use it:

List<Merchant> findTopMerchants(List<Merchant> merchants, int month) { // Local record record MerchantSales(Merchant merchant, // Use the MerchantSales Record class to temporarily wrap merchant and sales for easy handling. return merchants.stream() .map(merchant -> new MerchantSales(merchant, computeSales(merchant, month))) .sorted((m1, m2) -> Double.compare(m2.sales(), m1.sales())) .map(MerchantSales::merchant) .collect(toList()); }Copy the code

The Record class will be able to replace Tuple, Pair, etc., previously provided outside the JDK library Tuple function, in conjunction with the pattern matching feature will be described below, can make the code will be very concise.

Pattern matching

A pattern matching preview feature was introduced in JDK 14 and will be a permanent feature in JDK 16. So while JDK 16 is a short-term release, we will continue to use the pattern matching feature in future JDK releases.

Pattern matching at this stage is limited to one pattern (type pattern) and one language construct (instanceof), but this is only part of the complete feature. Even so, we have already achieved one significant benefit: redundant casts disappear, eliminating redundant code, bringing more important code into sharper focus, and eliminating places to hide bugs.

For example, when we need to parse objects in development, we use something like this

if (obj instanceof String) { String s = (String) obj; . }Copy the code

Equivalent code for pattern matching:

If (obj instanceof String s) {if (obj instanceof String s) { }Copy the code

Does the code look a lot cleaner?

Obtaining an object type using Instanceof is a form of conditional extraction, and after obtaining the object type, the object is always cast to that type.

The benefit of merging these operations, which previously had to be explicitly cast after Instanceof, is not just for brevity, it also eliminates a common source of error: By cutting and pasting instanceof and casting code, it’s easy to change the instanceof type and forget to change the cast type, giving vulnerabilities a hiding place. By eliminating this problem with Instanceof pattern matching, we can eliminate all these types of bugs as well.

Another place to do this kind of “check before cast” frequently is the equals method. Here’s another example:

if (! (o instanceof Point)) return false; Point other = (Point) o; return x == other.x && y == other.y; }Copy the code

Equivalent code for pattern matching:

public boolean equals(Object o) {
    return (o instanceof Point other)
        && x == other.x && y == other.y;
}
Copy the code

This code has the same effect, but is simpler and more direct, because we can express an equivalent condition using only a compound Boolean expression rather than a control flow statement.

The pattern-matching bound variable (s of obj instanceof String s in the code example above is a bound variable) has a different scope than “normal” local variables, in addition to its special declaration location.

For example, we could write:

if (a instanceof Point p) { // p is in scope ... } else { // p not in scope here } // p not in scope here if (b instanceof Point p) { // Sure! . }Copy the code

This special scope allows us to freely redeclare bound variables in if-else multi-branch cases, and it is also convenient to consider future cases in the Switch. Such as:

if (x instanceof Integer num) { ... }
else if (x instanceof Long num) { ... }
else if (x instanceof Double num) { ... }
Copy the code

If pattern matching could eliminate 99% of cast operations in Java code, it would certainly be popular. But it’s not limited to that. Over time, other types of patterns will emerge that can do more complex conditional extraction, combine patterns in more complex ways, and provide other constructs that can use patterns: With features like Switch and even Catch, as well as the Record class now permanently supported and the sealed class in preview, pattern matching promises to greatly simplify the code we write in the future.

The end of the

This article extracts 17 new features from the JDK version 16 to help with engineering work and learning of several features, quickly understand these features.

The majority of companies and projects still use JDK 8 (which still accounts for 80% of the JDK market, the absolute majority) due to the super luxurious new features of JDK 8, Examples include functional interfaces, Lambda expressions, method references/constructor references, stronger Steam apis, interface enhancements, Optional, Metaspace replacing PermGen space in the JVM, and more.

We can also see Java constantly innovating to keep up with the rapid pace of technological change.

Starting with JDK 9, Java releases have changed to every 6 months, with JDK 11 being the long-term support version and JDK 17 to be released later this year.

JDK 9~JDK15 also has some important new features, such as

  • JDK 9 module system, JShell interactive command line
  • JDK 10 Local variable type inference
  • JDK 11 ZGC trial, HTTP Client API, Steam and other enhancements
  • The JDK 12 Switch expression extension adds a suite of microbenchmarks based on the JMH
  • JDK 13 Socket API refactoring, text blocks (multiline text)
  • JDK 14 more valuable NPE error messages, and a partial preview of JDK 16 features
  • A preview of JDK 16 features such as the JDK 15 sealing class, the Record class, and more

Hopefully this strategy of rapid release iteration will keep Java alive and make it more efficient and robust for developers to use!

The resources

JDK 16 status, release schedule, and new features

JDK 16: The new features in Java 16

Migrate the Java source repository to Github

Run Spring Boot in the Alpine + OpenJDK image

JEP 394: Pattern Matching for instanceof

JEP 395: Records

JEP 397: Sealed Classes (Second Preview)

Join us

Welcome to join Amoy architecture team. The team has a large number of members, including founders of Ali Mobile Middleware, core members of Dubbo, and a group of partners who love technology and hope to promote business with technology.

Taoshi Architecture team promotes the architecture upgrade of Taoshi (Taobao, Tmall, etc.), and is committed to providing basic core capabilities, products and solutions for Taoshi and the whole group:

High-availability solutions and core capabilities (Refined traffic control) The Marconi platform provides adaptive flow control, isolation, and fusing flexible high-availability solutions for services. High-availability solutions for sites include fault self-healing, multi-room and remote disaster recovery, and fast cut-flow recovery

FaaS (Gaia Platform for One-stop Function Research and Development)

Implementation and implementation of the next generation network protocol QUIC

Mobile middleware (API gateway MTop, access layer AServer, message/push, configuration center, etc.)

Looking forward to joining the basic platform construction of Tao department ~

Resume to 📮 : Zak Bin [email protected] (Amoy Architecture – Application Architecture Leader)

  • Xiong Zheng (Ba Feng)
  • Source: Tao Technology public account