Java 14 features: Switch Expressions, JFR Event Streaming and more

This is the third post in a series of blog posts highlighting some features and improvements that will be introduced in Java 14, expected to go GA in a couple of days.
In this post, We will have a look into Switch expression, JFR streaming, as well as some various minor improvement.

Java 14 rew features articles:

Switch Expression (Standard): JEP 361

Switch expression was introduced first in JDK 12 as a preview feature, then refined in JDK 13 and it will be made final and permanent in JDK 14.

A look into Switch expression

Often, a switch statement produces a value in each of its case blocks. Switch expressions enable you to use more concise expression syntax: fewer repetitive case and break keywords and less error-prone.
Consider the following example:

        WeekDay day = WeekDay.FRIDAY;
        String dayType;
        switch (day) {
            case MONDAY:
            case TUESDAY:
            case WEDNESDAY:
            case THURSDAY:
            case FRIDAY:
                dayType = "Weekday";
                break;
            case SATURDAY:
            case SUNDAY:
                dayType = "Weekend";
                break;

            default:
                throw new IllegalArgumentException("Invalid Day");
        }

That's how we check if a specific day is a Weekday or not, using our good old switch statement. It would be better if we could return this information without the need of storing it in the variable dayType; we can do this with a switch expression which is both clearer and safer:

 String dayType = switch (day){
            case MONDAY, THURSDAY, WEDNESDAY, TUESDAY, FRIDAY -> "Weekday";
            case SATURDAY, SUNDAY -> "Weekend";
            default -> throw new IllegalArgumentException("Invalid Day");
        };

As you can notice, instead of having to break out different cases, we used the new switch lambda-style syntax, which allows the expression on the right to execute if the label matches. This is a more straightforward control flow, free of fall-through (No need for break statements).
Furthermore, the above example used "arrow case" labels with the arrow between label and execution. We could instead use "colon case" labels:

        String dayType = switch (day){
            case MONDAY, THURSDAY, WEDNESDAY, TUESDAY, FRIDAY:
                yield "Weekday";
            case SATURDAY, SUNDAY:
                yield "Weekend";
            default:
                throw new IllegalArgumentException("Invalid Day");
        };

But what is yield? yield statement has been introduced in JDK 13! It takes one argument, which is the value that the case label produces in a switch expression. This is an easy thumb of rule to differentiate between a switch expression and a switch statement.

JFR Event Streaming: JEP 349

Java Flight Recorder has a long history. It was first part of the BEA JRockit JVM. Then After Oracle acquired BEA it became a commercial feature of Oracle JDK. To be finally open sourced with the release of OpenJDK 11 (JEP 328) and also in the process to be backported to 8. The arrival of JDK 14 introduces a new feature to JFR: the ability for JFR to produce a continuous stream of events.

What is JFR?

JFR is basically a monitoring tool that collects information about the events in a Java Virtual Machine (JVM) during the execution of a Java application. It is designed to affect the performance of a running application as little as possible.

JFR in JDK 14

With JEP 349, a new usage mode for JFR becomes available, which is JFR Event Streaming. This API provides a way for programs to receive callbacks when JFR events occur and respond to them immediately for both in-process and out-of-process applications. Same set of events can be recorded as in the non-streaming way. Therefore, event streaming would be performed at the same time as non-streaming.
Check out the following example:

        Configuration config = Configuration.getConfiguration("default");
        try (var es = new RecordingStream(config)) {
            es.onEvent("jdk.GarbageCollection", System.out::println);
            es.onEvent("jdk.CPULoad", System.out::println);
            es.onEvent("jdk.JVMInformation", System.out::println);
            es.setMaxAge(Duration.ofSeconds(10));
            es.start();
        }

This snippet starts JFR on the local JVM using the default recorder settings and print the Garbage Collection, CPU Load and JVM Information events to standard output:

jdk.JVMInformation {  
  startTime = 12:13:28.724
  jvmName = "OpenJDK 64-Bit Server VM"
  jvmVersion = "OpenJDK 64-Bit Server VM (14+36-1461) for bsd-amd64 JRE (14+36-1461), built on Feb  6 2020 19:03:05 by "mach5one" with clang 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.11.45.5)"
  jvmArguments = N/A
  jvmFlags = N/A
  javaArguments = "me.aboullaite.JFRStreamTest"
  jvmStartTime = 12:13:28.415
  pid = 72713
}
jdk.CPULoad {  
  startTime = 12:13:30.682
  jvmUser = 0.98%
  jvmSystem = 0.08%
  machineTotal = 2.86%
}

NUMA-Aware Memory Allocation for G1: JEP 345

NUMA (Non-uniform memory access)is a method of configuring a cluster of microprocessor in a multiprocessing system so that they can share memory locally, improving performance and the ability of the system to be expanded.

This JEP aims to improve G1 performance on large machines by implementing NUMA-aware memory allocation. G1's heap is organized as a collection of fixed-size regions. A region is typically a set of physical pages, although when using large pages (via -XX:+UseLargePages) several regions may make up a single physical page. If the +XX:+UseNUMA option is specified then, when the JVM is initialized, the regions will be evenly spread across the total number of available NUMA nodes.

Non-Volatile Mapped Byte Buffers: JEP 352

This JEP improves FileChannel API to support creating mapped byte buffers on non-volatile memory (persistent memory). The only API change required is a new enumeration employed by FileChannel clients to request mapping of a file located on an NVM-backed file system rather than a conventional, file storage system. The new enumeration values are used when calling the FileChannel::map method to create, respectively, a read-only or read-write MappedByteBuffer mapped over an NVM device file. This feature is only supported in Linux/x64 and Linux/AArch64 platforms.

Deprecate the Solaris and SPARC Ports: JEP 362

Solaris/SPARC, Solaris/x64, and Linux/SPARC ports are deprecated and will be removed in a future release. The main motivation is to enable OpenJDK Community contributors to accelerate the development of new features, moving the platform forward.

Remove the Concurrent Mark Sweep (CMS) Garbage Collector: JEP 363

CMS Garbage Collected was deprecated in Java 9, and it is removed with Java 14.

ZGC on macOS (JEP 364) and Windows (JEP 365)

ZGC was introduced in Java 11, but it was only supported in Linux. Now it is also available in macOS and Windows. For windows ZGC is not supported on Windows 10 and Windows Server older than version 1803, since older versions lack the required API for placeholder memory reservations.

Deprecate the ParallelScavenge + SerialOld GC Combination: JEP 366

The Parallel Scavenge young and Serial old garbage collector combination is deprecated due to little use and significant amount of maintenance effort.

Remove the Pack200 Tools and API: JEP 367

Pack200 tools and api was deprecated in Java 11, and it is removed with Java 14.


Resources and further reading: