Java 14已于2020年3月17日正式发布,请在此处下载Java 14 。
Java 14功能。
- JEP 305:instanceof(预览)的模式匹配 (开发人员功能)
- JEP 343:包装工具(培养箱)
- JEP 345:针对G1的NUMA感知内存分配
- JEP 349:JFR事件流
- JEP 352:非易失性映射字节缓冲区
- JEP 358:有用的NullPointerExceptions
- JEP 359:记录(预览) (开发人员功能)
- JEP 361:开关表达式(标准) (开发人员功能)
- JEP 362:弃用Solaris和SPARC端口
- JEP 363:删除并发标记扫描(CMS)垃圾收集器
- JEP 364:macOS上的ZGC
- Windows上的JEP 365:ZGC
- JEP 366:弃用ParallelScavenge + SerialOld GC组合
- JEP 367:删除Pack200工具和API
- JEP 368:文本块(第二预览) (开发人员功能)
- JEP 370:外部存储器访问API(孵化器) (开发人员功能)
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
。
JEP 343:包装工具(培养箱)
新的jpackage
工具,用于将Java应用程序打包到特定于平台的程序包中。
- Linux:deb和rpm
- macOS:pkg和dmg
- Windows:MSI和EXE
例如,将JAR
文件打包到Windows上的exe
文件中。
PS Update jpackage
示例在这里
JEP 345:针对G1的NUMA感知内存分配
新的NUMA感知内存分配模式提高了大型计算机上的G1性能。 添加+XX:+UseNUMA
选项将其启用。
JEP 349:JFR事件流
改进了现有的JFR以支持事件流,这意味着现在我们可以实时传输JFR事件,而无需将记录的事件转储到磁盘并手动解析它。
JDK Flight Recorder(JFR)是用于收集有关正在运行的Java应用程序的诊断和性能分析数据的工具。 通常,我们开始记录,停止记录,将记录的事件转储到磁盘以进行分析,它可以很好地进行概要分析,分析或调试。
相关的 JEP 328:飞行记录器
PS Update JFR事件流示例在此处 _
JEP 352:非易失性映射字节缓冲区
改进的FileChannel
API可以创建MappedByteBuffer
来访问非易失性内存(NVM) ,该内存即使在关闭电源后也可以检索存储的数据。 例如,此功能可确保将可能仍在高速缓存中的所有更改写回到内存中。
PS仅Linux / x64和Linux / AArch64 OS支持此功能!
JEP 358:有用的NullPointerExceptions
通过告诉哪个变量为空,改进了对NullPointerExceptions
的描述。 添加-XX:+ShowCodeDetailsInExceptionMessages
选项以启用此功能。
抛出NullPointerException
简单Java文件。
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)
PS请默认启用此功能🙂
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(p1.equals(p3)); // true
}
}
使用--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
true
进一步阅读
有关更多record
示例,请参考此Java 14 Record数据类。
PS更新记录或数据类示例在这里
JEP 361:开关表达式(标准)
开关表达式是Java 12和Java 13中的预览功能。 现在它已正式成为JDK标准功能,这意味着从Java 14开始,我们可以通过开关表达式返回值,而无需指定--enable-preview
选项。
回顾一下; 我们可以使用yield
从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;
}
请参阅此Java 13 Switch Expression中的示例。
JEP 362:弃用Solaris和SPARC端口
放弃对Solaris / SPARC,Solaris / x64和Linux / SPARC端口的支持,更少的平台支持意味着更快地交付新功能。
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
JEP 364:macOS上的ZGC(实验性)
Java 11 – JEP 333在Linux上引入了Z垃圾收集器(ZGC),现在可移植到macOS。
Windows上的JEP 365:ZGC(实验性)
Java 11 – JEP 333在Linux上引入了Z垃圾收集器(ZGC),现在可移植到Windows版本== 1803。
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.
JEP 367:删除Pack200工具和API
Java 11 – JEP 336不推荐使用pack200
和unpack200
工具以及java.util.jar
软件包中的Pack200
API,现在正式将其删除。
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>
进一步阅读
有关更多Java文本块示例的信息,请参考此Java多行字符串,文本块
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();
System.out.println(base); // print memory address
intHandle.set(base, 999); // set value 999 into the foreign memory
System.out.println(intHandle.get(base)); // get the value from foreign memory
}
}
}
编译并使用孵化器模块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
进一步阅读– jdk.incubator.foreign Javadoc
$ git clone https://github.com/mkyong/core-java
$ cd java-14
参考文献
- OpenJDK 14项目
- Java 14引入了许多新功能
- Java版本历史
- 维基百科–非易失性存储器(NVM)
- 维基百科–非统一内存访问(NUMA)
- Java的数据类和密封类型
- jdk.incubator.foreign
- Java 13开关表达式
- Java 13文本块