Last Updated:

Java 14 中的新功能

银狐
Java 14 徽标

 

Java 14于 2020 年 3 月 17 日正式发布,请在此处下载 Java 14

Java 14 特性。

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:非易失性映射字节缓冲区

改进的FileChannelAPI 以创建MappedByteBuffer非易失性存储器 (NVM) 的访问- 一种即使在重新上电后也可以检索存储数据的存储器。例如,此功能可确保将可能仍在缓存中的任何更改写回内存。

PS 只有 Linux/x64 和 Linux/AArch64 操作系统支持这个!

进一步阅读

6. JEP 358:有用的 NullPointerExceptions

NullPointerExceptions通过告诉哪个变量为空来改进描述。添加-XX:+ShowCodeDetailsInExceptionMessages选项以启用此功能。

一个简单的 Java 文件,它抛出一个NullPointerException.

Test.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)

进一步阅读

7. JEP 359:记录(预览)

一个名为record(又名数据类)的新类,它是一个最终类,而不是抽象类,并且它的所有字段也是最终的。该record会自动生成繁琐constructorspublic getequals()hashCode()toString()在编译时。

PS 没有设置器,所有字段都是最终的。

一个record或数据类,创建类名和变量,我们就可以开始使用了。

Point.java

record Point(int x, int y) { }
Test.java

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

历史

  • Java 15 JEP 384具有记录的第二个预览版,具有密封类型、本地记录、记录注释和反射 API 等新功能。
  • Java 16 JEP 395,记录或数据类是标准特性。

进一步阅读

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过时的pack200unpack200工具,以及Pack200在APIjava.util.jar包,现在它被正式删除。

进一步阅读

15. JEP 368:文本块(第二次预览)

第一个预览出现在 Java 13 JEP 354 中,现在又添加了两个新的转义序列:

  • \<end-of-line> 抑制线路终止。
  • \s 被翻译成一个空格。
Test.java

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 堆之外的外部内存。

Test.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

历史

  • Java 15 JEP 383有第二个孵化器。
  • Java 16 JEP 393有第三个孵化器。

进一步阅读

下载源代码

$ git clone https://github.com/mkyong/core-java

$ cd java-14

参考