Java 14 new feature summary

Java 14 was released on March 17, 2020. Java SE 14 Platform JSR 389

download

You can download it from the OpenJDK site. https://jdk.java.net/14/

SDKMAN! is recommended for installation on Mac and Linux

Other than Oracle OpenJDK, the following distributions are available for commercial use free of charge.

Since it is not LTS, it does not seem to be released on Amazon Corretto. The update will be released in April with 14.0.1 and in July with 14.0.2.

You can use the Oracle JDK for development purposes, but you must purchase a Java SE Subscription for commercial use.

JEP Large changes are organized in JEP. https://openjdk.java.net/projects/jdk/14/

This time, 16 JEPs were imported. Many have a large impact. 305: Pattern Matching for instanceof (Preview) 343: Packaging Tool (Incubator) 345: NUMA-Aware Memory Allocation for G1 349: JFR Event Streaming 352: Non-Volatile Mapped Byte Buffers 358: Helpful NullPointerExceptions 359: Records (Preview) 361: Switch Expressions (Standard) 362: Deprecate the Solaris and SPARC Ports 363: Remove the Concurrent Mark Sweep (CMS) Garbage Collector 364: ZGC on macOS 365: ZGC on Windows 366: Deprecate the ParallelScavenge + SerialOld GC Combination 367: Remove the Pack200 Tools and API 368: Text Blocks (Second Preview) 370: Foreign-Memory Access API (Incubator)

I will summarize by field.

Language specifications

Some of the changes related to the language specification are as follows. 359: Records (Preview) 305: Pattern Matching for instanceof (Preview) 368: Text Blocks (Second Preview) 361: Switch Expressions (Standard)

359: Records (Preview)

Record has been added as a preview function as a class for data retention. An improved version that reflects feedback in Java 15 will be previewed and will be formalized in Java 16.

Define it as record.

record Foo(int x, int y) {}

Other classes cannot be inherited.

record record name(Status) {Definition}

This would be a class like this:

class Foo extends Record {
  //State defined as private final
  private final int x;
  private final int y;
  //No additional instance fields can be defined

  //A constructor that sets the state to the field is defined
  public Foo(int x, int y) {
    this.x = x;
    this.y = y;
  }

  //A method with the same name as the state is defined
  public int x() {
    return x;
  }
  public int y() {
    return y;
  }

  //A hashCode that reflects the state is defined
  public int hashCode() { ... }
  //Equals to compare states are defined
  public boolean equals() { ... }
  //A toString that displays the status is defined
  public String toString() { ... }
}

The method for getting is defined, but the method for setting the value is not defined. In other words, it is an immutable object. Also, since it is not get / set, it is not compatible with Java Bean. The hashCode () and ʻequals ()` methods are actually invokeDynamic and the implementation code is generated at runtime.

You can define constructors for state checking and normalization as follows:

record Range(int lo, int hi) {
  public Range {
    if (lo > hi) throw IllegalArgumentException();
    //Fields that were not set will be set later
  }
}

You cannot define record in a non-static inner class. Compiling code like the following will result in the error record declarations not allowed in inner classes.

public class NestedRecord {
  class Foo {
      record Bar(int x){}
  }
}

You can compile code like this:

public class NestedRecord {
  static class Foo {
      record Bar(int x){}
  }
}

API extension

record is a class that inherits java.lang.Record.

If you try to write code that inherits from Record as follows, you will get the error records cannot directly extend java.lang.Record.

class Foo extends Record {
}

Record-related methods have been added to the Class class. You can determine if the type is record with the ʻisRecordmethod. You can also get the components defined by record withgetRecordComponents`. However, it seems that the value can be obtained via Field because it cannot be obtained via RecordComponent.

jshell> Foo.class.isRecord()
$9 ==> true

jshell> Foo.class.getRecordComponents()
$10 ==> RecordComponent[2] { int x, int y }

jshell> String.class.isRecord()
$11 ==> false

jshell> String.class.getRecordComponents()
$12 ==> null

Limitation of record as a type name

It is restricted to give the name record to a type (such as a class interface record type). An error will occur if --enable-preview is added.

$ jshell --enable-preview
|Welcome to JShell--Version 14-ea
|For an overview, type:: /help intro

jshell> class record{}
|error:
|here'record'Is not allowed
|From release 13'record'Is a restricted type name and cannot be used to declare a type
|  class record{}
|        ^

jshell> String record=""
record ==> ""

jshell> record Rec(int record){}

jshell> Rec record=new Rec(3)
record ==> Rec[record=3]

By the way, this "from release 13" is wrong, but from 14. http://mail.openjdk.java.net/pipermail/amber-dev/2020-February/005623.html

Unlike enums, it's not a keyword, so you can use record for variable names, fields, and record component names. If you do not add --enable-preview, a warning will be displayed.

$ jshell
|Welcome to JShell--Version 14-ea
|For an overview, type:: /help intro

jshell> class record{}
|warning:
|  'record'May be a restricted type name in a future release and may not be used in type declarations or as an array element type
|  class record{}
|        ^
|Created the following:Class record

Future improvement

Initially it was the same JEP as Sealed Types, but it was separated. This function allows you to limit class inheritance to a limited number of classes. It seems to be in preview in Java 15. JEP 360: Sealed Types (Preview)

Improvements in Preview 2 are suggested here. https://mail.openjdk.java.net/pipermail/amber-spec-experts/2020-January/001913.html

-- java.util.Record is a class, but Valhalla's inline class can only inherit interface, so should this be an interface? --Visibility to required members (Is it strange that the members of private record are public?) --Currently, records cannot be nested in the inner class, which is not static, but I want to support it.

reference Feedback from Stephen Colebourne https://mail.openjdk.java.net/pipermail/amber-dev/2019-November/005271.html

305: Pattern Matching for instanceof (Preview)

It is pattern matching. First of all, pattern matching using instance of will be included in 14 as a preview. http://openjdk.java.net/jeps/305

You can match the values with the value instanceof pattern. The pattern is a constant or variable definition. In the case of a variable definition, if the types match, it becomes true and a value is assigned to that variable.

if (x instanceof Integer i) {
    // can use i here
}

It would be nice if it could be used with a switch, but it was defined in another JEP and carried over to Java 15. JEP draft: Pattern matching for switch (Preview)

Also, it seems that the function to decompose record (deconstruction) and its nesting are introduced and it will enter Java 15 as Preview 2. http://openjdk.java.net/jeps/8235186

As a reasonable schedule

Will it be

However, 17LTS has a prospect of including the pattern matching function as a standard function.

368: Text Blocks (Second Preview)

You can define a character string that includes line breaks. Enclose in " "" . In JDK13, there are some changes such as escaping line breaks in what was included as Preview in JDK13. It will be standard in JDK15.

// same as "You can write\ntwo line string.\n"
var str = """
  You can write
  two line string.
  """;

The start " "" cannot be followed by a string, and the indentation is based on the "" " or the shallowest part of the internal string.

var str = """
..You can write
..two line string.
  """;
var str = """
..  You can write
..  two line string.
  """;

You can also escape line breaks.

var str = """
  You can write \
  two line string, \
  but this is single.
  """;

This will be " You can write two line string, but this is single. ".

Spaces at the end of the line are removed. So, if you need a space at the end of the line, put \ s to indicate that you need a space.

var str = """
  test\s
  test \s
  """;

This will be " test_ \ ntest__ \ n ". (In Qiita, even if you put multiple spaces, it will be one space)

You cannot embed variables in a string. Instead, the formatted method is provided as an instance method, and you can now write:

var str = """
Hello,%Mr. s.
It's nice weather today, is not it.
  """.formatted("Kishida");

361: Switch Expressions (Standard)

You can now use the previously statement switch as an expression. Introduced as a preview in Java 12, specification changes in Java 13, and official features in Java 14. https://openjdk.java.net/jeps/361

Switch was a statement, but since many switches used it to assign values to the same variable or return in all cases, it can also be used as an expression so that it can be written efficiently. I will.

In other words, like this.

int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY -> 7;
    case THURSDAY, SATURDAY -> 8;
    case WEDNESDAY -> 9;
};

You can also return a value with yield.

int result = switch (s) {
    case "Foo":
        yield 1;
    case "Bar":
        yield 2;
    default:
        System.out.println("Neither Foo nor Bar, hmmm...");
        yield 3;
}

The basic form is to return a value with yield.

case LABEL: yield expression;

It seems that you can write like lambda as that syntax sugar.

case LABEL -> expression;

It also allows you to specify multiple values for case.

switch (day) {
    case MONDAY, FRIDAY, SUNDAY: 
        numLetters = 6;
        break;
    ...
};

Such case extensions are also valid for existing switch statements.

JVM As a behavior change of the JVM, there is a detailed message with NullPointerException. 358: Helpful NullPointerExceptions

358: Helpful NullPointerExceptions

I think Java programmers love NullPointerException. However, I was worried that the message would not be complete. In Java 14, you can now view detailed messages about NullPointerException.

For example, if you have the following code:

public class Sample {
  static String s;
  public static void main(String... args) {
    s.length();
  }
}

If you run it normally in Java 14, you will not see any special messages as in previous versions.

$ java Sample.java
Exception in thread "main" java.lang.NullPointerException
        at Sample.main(mysample.java:4)

If you execute it with the -XX: + ShowCodeDetailsInExceptionMessages option, you will see what the error occurred when you called what for what as follows.

$ java -XX:+ShowCodeDetailsInExceptionMessages Sample.java
Exception in thread "main" java.lang.NullPointerException:
    Cannot invoke "String.length()" because "Sample.s" is null
        at Sample.main(mysample.java:4)

This message construction is done when the message is retrieved, so it seems to have little impact on performance.

For JShell, add -R-XX: + ShowCodeDetailsInExceptionMessages.

$ jshell -R-XX:+ShowCodeDetailsInExceptionMessages
|Welcome to JShell--Version 14-ea
|For an overview, type:: /help intro

jshell> String[] strs = {null}
strs ==> String[1] { null }

jshell> strs[0].toUpperCase()
|Exception java.lang.NullPointerException: Cannot invoke "String.toUpperCase()" because "REPL.$JShell$11.strs[0]" is null
|        at (#2:1)

API The API changes are the following three JEPs. 349: JFR Event Streaming 370: Foreign-Memory Access API (Incubator) 352: Non-Volatile Mapped Byte Buffers In addition to this, there was addition of plural form support in CompactNumberFormat and a convenient method in StrictMath. In addition, the Packaging tool-related API, which will be discussed later in the Tools section, has been added as an Incubator, and the Pac200-related API has been removed.

The API differences are summarized here. DRAFT: API Differences Between Java SE 13 (build 33) & Java SE 14 (build 36)

349: JFR Event Streaming

Flight Recorder is a metric collection tool that is useful for analysis in the event of a failure, but it requires analysis of dump files, which is inconvenient for monitoring purposes. JFR Event Streaming adds easy-to-use functions for monitoring, such as event registration.

The JEP sample shows an example of event registration, but I added the output of the GC log to this.

import java.io.IOException;
import java.time.Duration;
import jdk.jfr.consumer.RecordingStream;
public class JFRStreamTest {
     
    public static void main(String[] args) throws IOException  {
         
        try (var rs = new RecordingStream()) {
            rs.enable("jdk.CPULoad").withPeriod(Duration.ofSeconds(1));
            rs.enable("jdk.JavaMonitorEnter").withThreshold(Duration.ofMillis(10));
            rs.onEvent("jdk.CPULoad", event -> {
                System.out.println(event.getFloat("machineTotal"));
            });
            rs.onEvent("jdk.JavaMonitorEnter", event -> {
                System.out.println(event.getClass("monitorClass"));
            });
            rs.onEvent("jdk.GarbageCollection", System.out::println);
            rs.start();
        }
    }
}

If you run it with -XX: StartFilghtRecording, Flight Recorder will start and the metrics will be displayed periodically.

$ java -XX:StartFlightRecording JFRStreamTest.java
Started recording 1. No limit specified, using maxsize=250MB as default.

Use jcmd 79660 JFR.dump name=1 filename=FILEPATH to copy recording data to file.
[1.715s][warning][os] Unable to resolve PDH index: (230)
[1.716s][warning][os] Please check the registry if this performance object/counter is disabled
{
  classLoader = null  name = "jdk/jfr/internal/PlatformRecorder"
  package = {
    name = "jdk/jfr/internal"
    module = {
      name = "jdk.jfr"
      version = "14-ea"
      location = "jrt:/jdk.jfr"
      classLoader = null    }
    exported = true
  }
  modifiers = 49
}

jdk.GarbageCollection {
  startTime = 13:51:48.973
  duration = 12.5 ms
  gcId = 1
  name = "G1New"
  cause = "G1 Evacuation Pause"
  sumOfPauses = 12.5 ms
  longestPause = 12.5 ms
}

You can see it at JDK Mission Control (JMC). If you keep JFR running, you can see that the event is recorded in the event browser. image.png

370: Foreign-Memory Access API (Incubator)

There are advantages and disadvantages to access memory outside the heap, using ByteBuffer, Unsafe, and JNI. When using direct buffer with ByteBuffer, it is limited to 2GB which can be handled by int, and memory release depends on GC. In the case of Unsafe, the performance is good, but as the name implies, it's not safe, and accessing freed memory causes the JVM to crash. With JNI you have to write C code and the performance is not good.

That's why the API that directly handles the memory outside the heap was introduced. The code looks like this:

VarHandle intHandle = MemoryHandles.varHandle(int.class);

try (MemorySegment segment = MemorySegment.allocateNative(100)) {
   MemoryAddress base = segment.baseAddress();
   for (int i = 0 ; i < 25 ; i++) {
        intHandle.set(base.offset(i * 4), i);
   }
}

352: Non-Volatile Mapped Byte Buffers

Supports ByteBuffer for non-volatile memory. A module called jdk.nio.mapmode was introduced, and the ʻExtendedMapMode` class was prepared in the package with the same name as a new MapMode.

Will be added.

var fc = FileChannel.open(path);
fc.map(ExtendedMapMode.READ_WRITE_SYNC, 0, 1024);

It feels like. An UnsupportedOperationException is thrown if the device is not non-volatile memory.

Also, it seems that BufferPoolMXBean can get the stats of persistent MappedByteBuffer under the name mapped --' non-volatile memory'.

@PreviewFeature

The introductory API for preview features like String.formatted had Deprecated in 13. In 14, @PreviewFeature was introduced as an internal annotation, and it was clarified that it is an API for the preview function. In 13 you could use it without --enable-preview, but in 14 you could use these APIs when you didn't specify --enable-preview

formatted(java.lang.Object...)Is an API that is part of the preview feature

I get an error like this.

Explicitly specify serialization related method fields with @Serial

I define related fields and methods for classes that can be serialized, but although they have a fixed signature, they are not checked at compile time and I could not confirm that they are defined correctly.

private static final long serialVersionUID

https://download.java.net/java/GA/jdk14/docs/api/java.base/java/io/Serial.html https://bugs.openjdk.java.net/browse/JDK-8217698

Compact Number Format plural support

One of the changes that is not JEP. In the case of German or Italian, there are variations like Million or Millionen in 1 million and 2 million, and it seems that it corresponds to it.

jshell> import java.text.*

jshell> var cnf = CompactNumberFormat.getCompactNumberInstance(Locale.GERMAN, NumberFormat.Style.LONG)
cnf ==> java.text.CompactNumberFormat@5088aaba

jshell> cnf.format(1_000_000)
$3 ==> "1 Million"

jshell> cnf.format(2_000_000)
$4 ==> "2 Millionen"

There is also a constructor that allows you to set your own rules according to the Unicode Language Plural Rules (https://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules).

Addition of convenient methods to StrictMath

Convenient methods have been added to StrictMath. Did you aim to make method references easier to use?

Increment, decrement, sign inversion, but when overflow I get an error.

jshell> StrictMath.incrementExact(3)
$5 ==> 4

jshell> StrictMath.incrementExact(Integer.MAX_VALUE)
|Exception java.lang.ArithmeticException: integer overflow
|        at Math.incrementExact (Math.java:968)
|        at StrictMath.incrementExact (StrictMath.java:849)
|        at (#4:1)

jshell> StrictMath.negateExact(Integer.MAX_VALUE)
$6 ==> -2147483647

jshell> StrictMath.negateExact(Integer.MIN_VALUE)
|Exception java.lang.ArithmeticException: integer overflow
|        at Math.negateExact (Math.java:1044)
|        at StrictMath.negateExact (StrictMath.java:909)
|        at (#7:1)

Overflow occurs with normal operators.

jshell> Integer.MAX_VALUE+1
$8 ==> -2147483648

jshell> Integer.MIN_VALUE
$9 ==> -2147483648

jshell> -Integer.MIN_VALUE
$10 ==> -2147483648

tool

As a tool change, the addition of jpackage is big. 343: Packaging Tool (Incubator) 367: Remove the Pack200 Tools and API

343: Packaging Tool (Incubator)

A tool for creating a Java application installer has been added. A related API has also been added, but it is an Incubator module. Windows requires light.exe and candle.exe, so you need to download them from https://wixtoolset.org and add them to your PATH.

I will try to make an installer for the following application.

import javax.swing.*;
public class App {
    public static void main(String[] args) {
        var f = new JFrame("My App");
        var t = new JTextArea();
        f.add(t);
        var b = new JButton("Hello");
        b.addActionListener(al -> t.append("Hello!\n"));
        f.add("North", b);
        f.setSize(500, 400);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }
}

The application must be a Jar file.

$ javac App.java
$ mkdir target
$ jar cf target/app.jar App.class
$ jpackage --name myapp --input target --main-jar app.jar --main-class App

This will create a 45MB installer with the name myapp.exe for Windows. In the case of modular JAR, the Java runtime of only the required modules will be installed automatically, but since I created a Jar file that does not support modules here, it is small if you create the minimum Java runtime using jlink. You will be able to create an installer.

$ jdeps --list-deps App.class
java.base
java.desktop
$ jlink --add-modules java.base,java.desktop --output jre
$ jpackage --name myapp --input target --main-jar app.jar --main-class App --runtime-image jre

This reduced the size of the installer to 27MB. The application size after installation is also reduced from 124MB to 74MB. For Windows, it is better to add --win-menu to add the app to the Windows menu.

367: Remove the Pack200 Tools and API

Pack200 was a tool for efficiently compressing Jar files, but it is removed because its main use case, Applet, is no longer in use and is no longer in use. Related APIs under java.util.jar will also be deleted.

GC There were five JEPs of changes related to GC. 363: Remove the Concurrent Mark Sweep (CMS) Garbage Collector 364: ZGC on macOS 365: ZGC on Windows 366: Deprecate the ParallelScavenge + SerialOld GC Combination 345: NUMA-Aware Memory Allocation for G1

363: Remove the Concurrent Mark Sweep (CMS) Garbage Collector Concurrent Mark & Sweep GC is removed from the source code. It was Deprecated in JEP 291 of Java 9, but no one appeared to take over the maintenance, so I will delete it. By doing so, it is expected that the maintenance cost of GC will be reduced and the development of other GCs will be accelerated.

364: ZGC on macOS/365:ZGConWindows

ZGC, which previously supported only Linux, now supports macOS and Windows. Initially, it was assumed that ZGC would be used only on production Linux servers, and macOS and Windows would only be used for development purposes, but there were also requests to run the IDE on ZGC, so macOS and Windows are also supported. It seems that it was decided to do it. Windows is compatible with Windows 10 ver 1803 or later. ZGC uses a mechanism to access physical memory with multiple addresses using virtual addresses, but it seems that ZGC can be run on Windows because paging file memory is supported from 1803 on Windows.

366: Deprecate the ParallelScavenge + SerialOld GC Combination

The combination of Prallel for the GC in the Young area and Serial for the GC in the Old area, which is rarely used but difficult to maintain, has been deprecated.

345: NUMA-Aware Memory Allocation for G1 Recently, NUMA (Non-Uniform Memory Access) architecture, in which memory access from each core is not equal, has become widespread. Parallel GC supported NUMA, but G1 did not. With this JEP, G1 also supports NUMA. However, the supported OS is Linux only.

JDK Changes related to the JDK itself are related to the release format and build policy. Java 14 now supports Solaris and SPARC with Deprecated. 362: Deprecate the Solaris and SPARC Ports

362: Deprecate the Solaris and SPARC Ports Support for Solaris / SPARC, Solaris / x64, and Linux / SPARC will be removed. As with the CMS removal, if you can show that there is a lot of demand, it will be withdrawn. Also, this is about the development of OpenJDK as open source, and there is a possibility that continued support for commercial distributions such as Oracle JDK will continue. It seems that the Java license fee does not matter so much when Solaris / SPARC is installed.

Recommended Posts

Java 12 new feature summary
Java 13 new feature summary
Java 10 new feature summary
Java 14 new feature summary
Java knowledge summary
Java Generics Summary
Java related summary
java1.8 new features
[Summary] Java environment preparation
effective java 3rd summary
Java static [Personal summary]
Java 8 lambda expression Feature
Thread safe summary ~ Java ~
Personal summary about Java
What's new in Java 8
JSF2.3 new function summary
java regular expression summary
What's new in Java 9,10,11
Summary of Java support 2018
Java design pattern summary
Java reserved word summary
Java8 Stream Rough Summary
Summary of revisions (new era) support by Java version
What is Java Assertion? Summary.
[Java] New Thread generation method (2)
[Java11] Stream Summary -Advantages of Stream-
Progate Java (Beginner) Review & Summary
New features from Java7 to Java8
[Java] Summary of regular expressions
[Java] Summary of operators (operator)
Java8 stream, lambda expression summary
Object-oriented summary by beginners (Java)
Summary of Java language basics
Java tips --Spring execution Summary
[Java] Summary of for statements
Summary of Java Math class
PrimeFaces 6.0.x New Features Summary
[Java11] Stream Usage Summary -Basics-
[Java] Summary of control syntax
Summary of java error processing
[Java] Summary of design patterns
[Java] New Thread generation method (1)
[Java] Summary of mathematical operations
New grammar for Java 12 Switch statements
Consideration on Java Persistence Framework 2017 (Summary) -1
[For beginners] Summary of java constructor
Java release date and EOL summary
Java 9 new features and sample code
Summary
AtCoder 400 points algorithm summary (Java edition)
Java
Java "pass by reference" problem summary
Java
Summary of object-oriented programming using Java
[Java Silver] Summary of access modifier points
Summary of in-house newcomer study session [Java]
How to make a Java calendar Summary
Memorandum of new graduate SES [Java basics]
[java] Summary of how to handle char
Summary of changes other than JEP of Java10
I tried the new era in Java