Java 14 中的新功能
Java 14于 2020 年 3 月 17 日正式发布,请在此处下载 Java 14。
Java 14 特性。
- 1. JEP 305:instanceof 的模式匹配(预览)
- 2. JEP 343:包装工具(孵化器)
- 3. JEP 345:G1 的 NUMA 感知内存分配
- 4. JEP 349:JFR 事件流
- 5. JEP 352:非易失性映射字节缓冲区
- 6. JEP 358:有用的 NullPointerExceptions
- 7. JEP 359:记录(预览)
- 8. JEP 361:开关表达式(标准)
- 9. JEP 362:弃用 Solaris 和 SPARC 端口
- 10. JEP 363:移除并发标记清除 (CMS) 垃圾收集器
- 11. JEP 364:macOS 上的 ZGC(实验性)
- 12. JEP 365:Windows 上的 ZGC(实验性)
- 13. JEP 366:弃用 ParallelScavenge + SerialOld GC 组合
- 14. JEP 367:删除 Pack200 工具和 API
- 15. JEP 368:文本块(第二次预览)
- 16. JEP 370:外部内存访问 API(孵化器)
Java 14 开发人员功能。
开关表达式(标准)、记录(预览)、模式匹配(预览)、文本块或多行(第二预览)、外部内存访问 API(孵化器)
1. JEP 305:instanceof 的模式匹配(预览)
在 Java 14 之前,我们使用instanceof-and-cast
检查对象的类型并将其转换为变量。
if (obj instanceof String) { // instanceof
String s = (String) obj; // cast
if("jdk14".equalsIgnoreCase(s)){
//...
}
}else {
System.out.println("not a string");
}
现在 Java 14,我们可以像这样重构上面的代码:
if (obj instanceof String s) { // instanceof, cast and bind variable in one line.
if("jdk4".equalsIgnoreCase(s)){
//...
}
}else {
System.out.println("not a string");
}
如果obj
是 的实例String
,则将其强制转换为String
并分配给绑定变量s
。
历史
这种模式匹配是 Java 16, JEP 394 中的标准特性。
进一步阅读
2. JEP 343:包装工具(孵化器)
jpackage
将 Java 应用程序打包到特定于平台的包中的新工具,例如:
- Linux:deb 和 rpm
- macOS:pkg 和 dmg
- Windows:msi 和 exe
PS 这个打包工具是 Java 16 的标准特性,访问这个jpackage
例子。
进一步阅读
3. JEP 345:G1 的 NUMA 感知内存分配
新的NUMA-aware 内存分配模式,提高了大型机器上的 G1 性能。添加+XX:+UseNUMA
选项以启用它。
进一步阅读
4. JEP 349:JFR 事件流
改进了现有的 JFR 以支持事件流,这意味着现在我们可以实时流式传输 JFR 事件,而无需将记录的事件转储到磁盘并手动解析。
JDK Flight Recorder (JFR) 是一种用于收集有关正在运行的 Java 应用程序的诊断和分析数据的工具。通常,我们开始记录,停止记录,将记录的事件转储到磁盘进行解析,它适用于分析、分析或调试。
进一步阅读
5. JEP 352:非易失性映射字节缓冲区
改进的FileChannel
API 以创建MappedByteBuffer
对非易失性存储器 (NVM) 的访问- 一种即使在重新上电后也可以检索存储数据的存储器。例如,此功能可确保将可能仍在缓存中的任何更改写回内存。
PS 只有 Linux/x64 和 Linux/AArch64 操作系统支持这个!
进一步阅读
6. JEP 358:有用的 NullPointerExceptions
NullPointerExceptions
通过告诉哪个变量为空来改进描述。添加-XX:+ShowCodeDetailsInExceptionMessages
选项以启用此功能。
一个简单的 Java 文件,它抛出一个NullPointerException
.
import java.util.Locale;
public class Test {
public static void main(String[] args) {
String input = null;
String result = showUpperCase(input); // NullPointerException
System.out.println(result);
}
public static String showUpperCase(String str){
return str.toUpperCase(Locale.US);
}
}
在 Java 14 之前。
$ /usr/lib/jvm/jdk-14/bin/java Test
Exception in thread "main" java.lang.NullPointerException
at Test.showUpperCase(Test.java:15)
at Test.main(Test.java:9)
带-XX:+ShowCodeDetailsInExceptionMessages
选项的Java 14 。
$ /usr/lib/jvm/jdk-14/bin/java -XX:+ShowCodeDetailsInExceptionMessages Test
Exception in thread "main" java.lang.NullPointerException:
Cannot invoke "String.toUpperCase(java.util.Locale)" because "<parameter1>" is null
at Test.showUpperCase(Test.java:15)
at Test.main(Test.java:9)
进一步阅读
7. JEP 359:记录(预览)
一个名为record
(又名数据类)的新类,它是一个最终类,而不是抽象类,并且它的所有字段也是最终的。该record
会自动生成繁琐constructors
,public get
,equals()
,hashCode()
,toString()
在编译时。
PS 没有设置器,所有字段都是最终的。
一个record
或数据类,创建类名和变量,我们就可以开始使用了。
record Point(int x, int y) { }
public class Test {
public static void main(String[] args) {
Point p1 = new Point(10, 20);
System.out.println(p1.x()); // 10
System.out.println(p1.y()); // 20
Point p2 = new Point(11, 22);
System.out.println(p2.x()); // 11
System.out.println(p2.y()); // 22
Point p3 = new Point(10, 20);
System.out.println(p3.x()); // 10
System.out.println(p3.y()); // 20
System.out.println(p1.hashCode()); // 330
System.out.println(p2.hashCode()); // 363
System.out.println(p3.hashCode()); // 330
System.out.println(p1.equals(p2)); // false
System.out.println(p1.equals(p3)); // true
System.out.println(p2.equals(p3)); // false
}
}
用--enable-preview
.
$ /usr/lib/jvm/jdk-14/bin/javac --enable-preview --release 14 Point.java
$ /usr/lib/jvm/jdk-14/bin/javac --enable-preview --release 14 Test.java
$ /usr/lib/jvm/jdk-14/bin/java --enable-preview Test
输出
10
20
11
22
10
20
330
363
330
false
true
false
历史
进一步阅读
8. JEP 361:开关表达式(标准)
switch 表达式是 Java 12 和 Java 13 中的一个预览特性;现在它是正式的 JDK 标准特性,这意味着从 Java 14 及以后,我们可以通过 switch 表达式返回值,而无需指定--enable-preview
选项。
查看回顾;我们可以用来yield
从 a 返回一个值switch
。
private static int getValueViaYield(String mode) {
int result = switch (mode) {
case "a", "b":
yield 1;
case "c":
yield 2;
case "d", "e", "f":
// do something here...
System.out.println("Supports multi line block!");
yield 3;
default:
yield -1;
};
return result;
}
或者通过标签规则或箭头。
private static int getValueViaArrow(String mode) {
int result = switch (mode) {
case "a", "b" -> 1;
case "c" -> 2;
case "d", "e", "f" -> {
// do something here...
System.out.println("Supports multi line block!");
yield 3;
}
default -> -1;
};
return result;
}
进一步阅读
9. JEP 362:弃用 Solaris 和 SPARC 端口
放弃对 Solaris/SPARC、Solaris/x64 和 Linux/SPARC 端口的支持,更少的平台支持意味着更快地交付新功能。
PS Java 15 JEP 381删除了上述端口。
进一步阅读
10. JEP 363:移除并发标记清除 (CMS) 垃圾收集器
Java 9 JEP 291弃用了这个并发标记清除 (CMS) 垃圾收集器,现在它被正式删除。
/usr/lib/jvm/jdk-14/bin/java -XX:+UseConcMarkSweepGC Test
OpenJDK 64-Bit Server VM warning: Ignoring option UseConcMarkSweepGC; support was removed in 14.0
进一步阅读
11. JEP 364:macOS 上的 ZGC(实验性)
Java 11 JEP 333在 Linux 上引入了 Z 垃圾收集器 (ZGC),现在它可以移植到 macOS。
PS 此 ZGC 是 Java 15 JEP 377 中的产品特性。
进一步阅读
12. JEP 365:Windows 上的 ZGC(实验性)
Java 11 JEP 333在 Linux 上引入了 Z 垃圾收集器 (ZGC),现在它移植到 Windows 版本 >= 1803。
PS 此 ZGC 是 Java 15 JEP 377 中的产品特性。
进一步阅读
13. JEP 366:弃用 ParallelScavenge + SerialOld GC 组合
由于使用较少且维护工作量大,Java 14 弃用了并行年轻代和串行年老代 GC 算法的组合。
/usr/lib/jvm/jdk-14/bin/java -XX:-UseParallelOldGC Test
OpenJDK 64-Bit Server VM warning: Option UseParallelOldGC was deprecated in version 14.0 and will likely be removed in a future release.
进一步阅读
14. JEP 367:删除 Pack200 工具和 API
Java的11 JEP 336过时的pack200
和unpack200
工具,以及Pack200
在APIjava.util.jar
包,现在它被正式删除。
进一步阅读
15. JEP 368:文本块(第二次预览)
第一个预览出现在 Java 13 JEP 354 中,现在又添加了两个新的转义序列:
\<end-of-line>
抑制线路终止。\s
被翻译成一个空格。
public class Test {
public static void main(String[] args) {
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, World</p>\n" +
" </body>\n" +
"</html>\n";
String java13 = """
<html>
<body>
<p>Hello, World</p>
</body>
</html>
""";
String java14 = """
<html>
<body>\
<p>Hello, '\s' World</p>\
</body>
</html>
""";
System.out.println(html);
System.out.println(java13);
System.out.println(java14);
}
}
$ /usr/lib/jvm/jdk-14/bin/javac --enable-preview --release 14 Test.java
$ /usr/lib/jvm/jdk-14/bin/java --enable-preview Test
输出
html>
<body>
<p>Hello, World</p>
</body>
</html>
<html>
<body>
<p>Hello, World</p>
</body>
</html>
<html>
<body> <p>Hello, ' ' World</p> </body>
</html>
PS 此文本块是 Java 15 中的永久功能。
进一步阅读
16. JEP 370:外部内存访问 API(孵化器)
一个孵化器模块,允许 Java API 访问 Java 堆之外的外部内存。
import jdk.incubator.foreign.*;
import java.lang.invoke.VarHandle;
import java.nio.ByteOrder;
public class Test {
public static void main(String[] args) {
VarHandle intHandle = MemoryHandles.varHandle(
int.class, ByteOrder.nativeOrder());
try (MemorySegment segment = MemorySegment.allocateNative(1024)) {
MemoryAddress base = segment.baseAddress();
// print memory address
System.out.println(base);
// set value 999 into the foreign memory
intHandle.set(base, 999);
// get the value from foreign memory
System.out.println(intHandle.get(base));
}
}
}
编译并运行 incubator 模块jdk.incubator.foreign
。
$ /usr/lib/jvm/jdk-14/bin/javac --add-modules jdk.incubator.foreign Test.java
warning: using incubating module(s): jdk.incubator.foreign
1 warning
$ /usr/lib/jvm/jdk-14/bin/java --add-modules jdk.incubator.foreign Test
WARNING: Using incubator modules: jdk.incubator.foreign
MemoryAddress{ region: MemorySegment{ id=0x4aac6dca limit: 1024 } offset=0x0 }
999
历史
进一步阅读
下载源代码
$ git clone https://github.com/mkyong/core-java
$ cd java-14