Java 14 特性

保持每六个月发布一次的传统,在2019年9月17日发布了Java 13之后,另一个非LTS版本的Java 14定于2020年3月17日发布。

Java 14功能

以下是Java 14的功能列表:

  • Switch表达式(标准)- JEP 361
  • 用于instanceof的模式匹配(预览)- JEP 305
  • 有用的NullPointerExceptions – JEP 358
  • Records(预览)- JEP 359
  • 文本块(第二预览)- JEP 368
  • 打包工具(孵化器)- JEP 343
  • 针对G1的NUMA感知内存分配 – JEP 345
  • JFR事件流式传输 – JEP 349
  • 非易失性映射字节缓冲区 – JEP 352
  • 在macOS上的ZGC – JEP 364
  • 在Windows上的ZGC – JEP 365
  • 外部内存访问API(孵化器)- JEP 370

在Mac OS上设置Java 14安装

  • 开始使用Java 14,从这里下载JDK。
  • 将tar文件复制并解压缩到/Library/Java/JavaVirtualMachines,如下所示:
$ cd /Library/Java/JavaVirtualMachines

$ sudo cp ~/Downloads/openjdk-14_osx-x64_bin.tar.gz /Library/Java/JavaVirtualMachines

$ sudo tar xzf openjdk-14_osx-x64_bin.tar.gz

$ sudo rm openjdk-14_osx-x64_bin.tar.gz

完成后,使用任何文本编辑器打开bash_profile。我使用vim ~/.bash_profile。将Java 14的路径设置为JAVA_HOME,保存更改,然后执行source ~/.bash_profile以反映更改。

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-14.jdk/Contents/Home

最后,您可以使用Java 14编译和运行程序。我们将使用JShell,这是一个交互式REPL命令行工具,用于快速测试新的Java 14功能。

重要的是要注意,Java 14中发布的许多功能都处于预览阶段。这意味着尽管它们现在完全可用,但将来可能会进行修改。在未来的发布周期中,其中一些功能可能会变为标准,或者可能会被移除。为了测试预览功能,您需要在运行JShell或Java程序时显式设置--enable-preview,如下所示:

jshell --enable-preview

javac --release 14 --enable-preview Author.java

在接下来的几节中,让我们讨论一些语言和JVM功能。

推荐阅读: 在Linux上安装Java 14

1. Switch表达式

在过去的两个版本中,Switch表达式作为试验性功能保留,Java 12和Java 13终于在Java 14中获得了永久的地位。

  • Java 12引入了lambda语法用于switch表达式,从而允许多个case标签进行模式匹配,并且防止了导致冗长代码的穿透。它还强制了全面的case覆盖,如果没有涵盖所有输入情况,则会抛出编译错误。
  • Java 13作为第二个试验性功能引入了yield语句,用于从表达式返回值,而不是使用break语句。

Java 14终于将这些功能正式纳入标准。

String result = switch (day) {
            case "M", "W", "F" -> "MWF";
            case "T", "TH", "S" -> "TTS";
            default -> {
                if(day.isEmpty())
                    yield "Please insert a valid day.";
                else
                    yield "Looks like a Sunday.";
            }

        };
System.out.println(result);
Java 14 Switch Expressions

注意:yield并不是Java中的新关键字,它只是在switch表达式中使用的。

2. instanceof的模式匹配(试验性)

请任何Java开发人员展示他们的代码库,你会看到代码中充斥着对instanceof条件的使用。特别是,在instanceof条件检查之后通常会进行类型转换。

Java 14通过使条件提取更加简洁来消除这种冗长性。

Java 14之前:

if (obj instanceof Journaldev) {
  Journaldev jd = (Journaldev) obj;
  System.out.println(jd.getAuthor());
}

Java 14及以后:

if (obj instanceof Journaldev jd) {
  System.out.println(jd.getAuthor());
}

在上述代码中,只有当obj的类型是Journaldev时,实例jd才会被赋值。变量的范围仅限于条件块内部。

3. 有用的空指针异常

对于任何开发人员来说,空指针异常都是一场噩梦。在Java 13之前,要调试臭名昭著的NPE是有技巧的。开发人员必须依靠其他调试工具或手动找出变量/方法为空的情况,因为堆栈跟踪只会显示行号。

Java 14之前:

String name = jd.getBlog().getAuthor()

//堆栈跟踪
Exception in thread "main" java.lang.NullPointerException
    at NullPointerExample.main(NullPointerExample.java:5)

Java 14引入了一个新的JVM特性,通过更具描述性的堆栈提供更好的见解,如下所示:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Blog.getAuthor()" because the return value of "Journaldev.getBlog()" is null
    at NullPointerExample.main(NullPointerExample.java:4)

注意:上述特性不是语言特性。这是运行时环境的增强。

4. 记录(预览)

A record is a data class that stores pure data. The idea behind introducing records is to quickly create simple and concise classes devoid of boilerplate code.

通常,Java中的类需要您实现equals()hashCode()以及getter和setter方法。虽然一些集成开发环境支持自动生成这些类,但代码仍然冗长。使用record,您只需按以下方式定义一个类。

record Author(){}
//或者
record Author (String name, String topic) {}

Java 编译器会自动生成一个构造函数、私有 final 字段、访问器、equals/hashCodetoString 方法。上述类的自动生成的 getter 方法为 name()topic()

要查看生成的代码,请在使用 javac 编译程序后使用 javap Author。下面的示例展示了为 record Author (String name, String topic) {} 生成的类:

Javap Records Java 14

记录的语义类似于 Kotlin 中的 Data Classes

此外,我们可以通过以下方式向记录添加额外的字段、方法和构造函数:

record Author (int id, String name, String topic) {
    static int followers;

    public static String followerCount() {
        return "Followers are "+ followers;
    }

    public String description(){
        return "Author "+ name + " writes on "+ topic;
    }

    public Author{
    if (id < 0) {
        throw new IllegalArgumentException( "id must be greater than 0.");
     }
   }
}

在记录内部定义的额外构造函数被称为紧凑构造函数。它不包含任何参数,只是规范构造函数的扩展。

A compact constructor wouldn’t be generated as a separate constructor by the compiler. Instead, it is used for validation cases and would be invoked at the start of the main constructor.

关于记录的一些重要注意事项:

  • A record can neither extend a class nor it can be extended by another class. It’s a final class.
  • 记录不能是抽象的
  • 记录不能扩展任何其他类,也不能在主体内定义实例字段。实例字段必须仅在状态描述中定义
  • 声明的字段是私有的和 final 的
  • 记录的主体允许静态字段和方法

推荐阅读: Java Records

4.1) 记录中参考字段内的值可以被改变

需要注意的是,对于定义为对象的字段,只有引用是不可变的。底层的值可以被修改。下面的示例展示了一个记录,在其中 ArrayList 被修改。正如你所看到的,每当 ArrayList 被改变时,值都会被修改。

Java 14 Records Mutable Values For References

4.2) 记录可以实现接口

以下代码展示了使用记录实现接口的示例:

record Author(String name, String topic) implements Information {
  public String getFullName() {
    return "Author "+ name + " writes on " + topic;
  }
}

interface Information {
  String getFullName();
}

以下是上述代码在 JShell 中运行的输出:

Java 14 Records With Interface

4.3) 记录支持多个构造函数

记录允许声明多个构造函数,可以有参数也可以没有,如下所示:

record Author(String name, String topic) {
  public Author() {

    this("NA", "NA");
  }

  public Author(String name) {

    this(name, "NA");
  }
}

4.4) 记录允许修改访问器方法

虽然记录确实为状态描述中定义的字段生成公共访问器方法,但它们也允许您在下面示例中重新定义访问器方法:

record Author(String name, String topic) {
  public String name() {
        return "This article was written by " + this.name;
    }
}

4.5) 在运行时检查记录及其组件

记录为我们提供了isRecord()getRecordComponents()来检查类是否为记录,并查看其字段和类型。以下示例显示了如何操作:

Java 14 Records Runtime Check

虽然我们在上述代码示例中添加了额外的字段和方法到记录中,但请确保不要过度。记录被设计为纯数据载体,如果您想要实现大量的额外方法,最好退回到普通类。

5. 文本块(预览)

文本块作为 Java 13 中的预览功能引入,旨在实现轻松创建多行字符串文字。它在轻松创建 HTML、JSON 或 SQL 查询字符串方面非常有用。

在 Java 14 中,文本块仍然处于预览状态,并进行了一些新的添加。我们现在可以使用:

  • 反斜杠来显示漂亮的多行字符串块。
  • \s 用于考虑默认情况下编译器忽略的尾随空格。它保留了它之前存在的所有空格。
String text = """
                Did you know \
                Java 14 \
                has the most features among\
                all non-LTS versions so far\
                """;

String text2 = """
                line1
                line2 \s
                line3
                """;


String text3 = "line1\nline2 \nline3\n"

//text2 和 text3 是相等的。

参考资料: OpenJDK 14

Source:
https://www.digitalocean.com/community/tutorials/java-14-features