Java 14 was released on March 17, 2020. Java SE 14 Platform JSR 389
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.
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){}
}
}
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 with
getRecordComponents`. 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
record
as a type nameIt 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
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.
@Deprecated
to record componentreference 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.
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.
READ_ONLY_SYNC
READ_WRITE_SYNC
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.
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
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).
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
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