Java 15的新特性
按照每六个月发布一次的惯例,在2020年3月17日发布了Java 14之后,我们现在即将迎来2020年9月15日发布的Java 15,这是接下来的非LTS版本。
Java 15 特性
以下是Java 15中的一些特性简要介绍:
- Sealed Classes (Preview) – JEP 360
- Pattern Matching for instanceof (Second Preview) – JEP 375
- Records (Second Preview) – JEP 359
- Text Blocks (Standard) – JEP 378
- Hidden Classes – JEP 371
- Remove the Nashorn JavaScript Engine – JEP 372
- Reimplement the Legacy DatagramSocket API – JEP 373
- Disable and Deprecate Biased Locking – JEP 374
- Shenandoah: A Low-Pause-Time Garbage Collector – JEP 379
- Remove the Solaris and SPARC Ports – JEP 381
- Foreign-Memory Access API (Second Incubator) – JEP 383
- Deprecate RMI Activation for Removal – JEP 385
在Mac OS上安装Java 15设置
- To get started with Java 15, download the JDK from here.
- Copy and extract the tar file in the /Library/Java/JavaVirtualMachines as shown below:
$ cd /Library/Java/JavaVirtualMachines
$ sudo cp ~/Downloads/openjdk-15_osx-x64_bin.tar.gz /Library/Java/JavaVirtualMachines
$ sudo tar xzf openjdk-15_osx-x64_bin.tar.gz
$ sudo rm openjdk-15_osx-x64_bin.tar.gz
完成后,使用任何文本编辑器打开bash_profile文件。我正在使用vim ~/.bash_profile命令。将Java 15的路径设置为JAVA_HOME,保存更改并执行source ~/.bash_profile命令以反映更改。
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-15.jdk/Contents/Home
最后,你准备好使用Java 15编译和运行程序了。我们将使用JShell,一个交互式REPL命令行工具,快速测试新的Java 15特性。
请注意,Java 15中发布的许多功能处于预览状态。这意味着虽然它们目前完全可用,但以后可能会进行修改。一些功能可能会成为标准,或在下一个发布周期中被删除。为了测试预览功能,您需要在运行JShell或Java程序时显式设置–enable-preview,如下所示:
jshell --enable-preview
javac --release 15 --enable-preview Author.java
在接下来的几个部分中,让我们讨论一下Java 15中的重大语言变化。
1. 封闭类型 (预览)
自从 Kotlin 推出以来,密封类一直存在,并且 Java 15 最终引入了这一特性,以提供更好对继承进行控制的功能。
正如其名,封闭类可以让您限制或允许仅特定类型的类继承关系。
这对于模式匹配非常有用,因为您可以在一组特定的类别之间进行切换。
以下语法在Java 15中定义了一个密封类:
public sealed class Vehicle permits Car, Bike, Truck {
...
}
所以,上述代码意味着只有在关键字”允许”之后定义的类才可以扩展Vehicle密封类。
如果你已经在同一个文件中定义了Car、Bike和Truck这些类,你可以省略关键字permits,编译器会隐式地处理它,如下所示:
sealed class Vehicle {...}
final class Car extends Vehicle {...}
final class Bike extends Vehicle {...}
final class Truck extends Vehicle {...}
正如你在上面所看到的,我们已经定义了每个类的最终修饰符。现在,这是一个关于密封类的重要规则,你需要记住:每个允许的类都必须设置一个明确的修饰符。它可以是final、sealed或者non-sealed之一。
以下是每个修饰词对继承产生的影响:
- A permitted subclass that’s declared final cannot be extended further.
- A permitted subclass that’s declared sealed can be extended further but only by classes that are permitted by the subclass.
- A permitted subclass may be declared non-sealed can be extended further by any class. The superclass cannot restrict the subclasses further down this class hierarchy.
在Java 15之前,开发人员只能使用final关键字或范围修饰符来控制继承。因此,封闭类为Java开发人员在定义类层次结构时带来了额外的灵活性。
Java的反射API还提供了两种处理封装类的新方法。
java.lang.constant.ClassDesc[] getPermittedSubclasses();
boolean isSealed()
2. 记录(第二个预览)
在Java 14中,记录作为一项预览功能被引入,旨在减少在编写基于POJO的数据承载类时的样板代码。这在Kotlin中早就存在,以数据类的形式。
现在,Java 15 推出了记录(Records)的第二个预览版本。虽然没有进行大的改动(只是一些小的添加),但是有一些重要的澄清和限制需要您了解。
- Prior to Java 15, one could declare native methods in records(though it wasn’t a good idea). Now the JEP explicitly prohibits against declaring native methods in records. Understandably, defining a native method steals away the USP of records by bringing an external state dependency.
- The implicitly declared fields corresponding to the record components of a record class are final and should not be modified via reflection now as it will throw IllegalAccessException.
记录应该是数据载体类,你应该完全避免在其中定义本地方法。
封装类型的记录
我们知道记录是最终的,不能被扩展。幸运的是,记录可以实现接口。
所以您可以定义一个封闭接口,并以以下方式在您的记录中实现它们:
sealed interface Car permits BMW, Audi { ... }
record BMW(int price) implements Car { ... }
record Audi(int price, String model) implements Car { ... }
本地记录
在方法中,可以定义记录来存储中间值。与局部类不同,局部记录是隐式静态的。这意味着它们无法访问封装方法的变量和实例成员,这实际上是很好的,因为它防止了记录捕获值。
本地记录对于以前必须创建辅助记录的Java开发人员来说是一个巨大的福利。
通过引入本地记录,可以看到如何使用以下方法在流API中执行值的计算。
List<Merchant> findTopMerchants(List<Merchant> merchants, int month) {
// Local record
record MerchantSales(Merchant merchant, double sales) {}
return merchants.stream()
.map(merchant -> new MerchantSales(merchant, computeSales(merchant, month)))
.sorted((m1, m2) -> Double.compare(m2.sales(), m1.sales()))
.map(MerchantSales::merchant)
.collect(toList());
}
结论
在Java 15中,上述两个是主要的语言特性,我们还有第二个预览版的模式匹配供用户反馈,文本块现在成为了标准特性,还有一项重要的新隐藏类特性。
隐藏类是一个与框架开发人员相关的JVM功能。它允许通过Lookup::defineHiddenClass定义类实现,使其无法被发现。通过这种方式,这些类既无法使用Class.forName找到,也无法通过字节码直接引用。
以下是Java 15引入的主要变更。