JDK14总共有非常令人印象深刻的16个JDK增强建议(JEP)和69个新的API元素。
让我们从介绍Java语言语法更改的更重要的项目开始。
记录
Java是一种面向对象的语言。您可以创建类来保存数据,并使用封装来控制如何访问和修改该数据。对象的使用使操作复杂的数据类型变得简单而直接。这是Java如此流行作为平台的原因之一。
缺点(到现在为止)是,创建数据类型非常冗长,即使在最直接的情况下也需要大量代码。让我们看一下基本二维点所需的代码:
public class Point { private final double x; private final double y; public Point(double x, double y) { this.x = x; this.y = y; } public double getX() { return x; } public double getY() { return y; } }
JDK 14引入了记录作为 预览功能 。预览功能是一个新概念,使Java平台的开发人员可以在不使其成为Java SE标准一部分的情况下包括新的语言功能。通过这样做,开发人员可以尝试这些功能,并提供反馈,以便在必要时在标准中设置功能之前进行更改(甚至删除功能)。要使用预览功能,必须为编译和运行时指定命令行标志--enable-preview。对于编译,还必须指定-source标志。
记录是表示数据类的一种简单得多的方法。如果以Point为例,代码可以简化为一行:
public record Point(double x, double y) { }
这与代码的可读性无关。我们立即意识到,我们现在有了一个包含两个称为x和y的双精度值的类,我们可以使用getX和getY的标准访问器方法名称进行访问。
让我们检查一下记录的一些细节。
首先,记录是一种新的类型,它是类的受限形式,就像枚举一样。记录具有名称和状态描述,用于定义记录的组成部分。在上面的Point示例中,状态描述是double和x和y。记录是为了简化而设计的,因此它们不能扩展任何其他类或定义其他实例变量。记录中的所有状态都是最终状态,因此不提供访问器(设置器)方法。如果您需要任何一个,则需要使用成熟的类。
记录确实具有灵活性。
通常,构造函数除了提供值外还需要提供其他行为。如果是这种情况,我们可以提供构造函数的替代实现:
record Range(int min, int max) { Range { if (min > max) throw new IllegalArgumentException(“Max must be >= min”); } }
模式匹配instanceof
在某些情况下,您不知道对象的确切类型。为了解决这个问题,Java有instanceof运算符,可用于针对不同类型进行测试。这样做的缺点是确定了对象的类型。如果要使用显式类型转换,则必须使用显式类型转换:
if (o instanceof String) { String s = (String)o; System.out.println(s.length); }
在JDK 14中,对instanceof运算符进行了扩展,以允许除了类型之外还指定变量名。然后可以使用该变量而无需显式强制转换:
if (o instanceof String s) System.out.println(s.length);
变量的范围限于在逻辑上正确使用的地方,因此:
if (o instanceof String s) System.out.println(s.length); else // s is out of scope here
作用域在也可以在条件语句中应用,因此我们可以执行以下操作:
if (o instanceof String s && s.length() > 4) ...
在下面情况下,无论o是否为String的结果,都需要对s.length()进行求值。从逻辑上讲,这不起作用,因此会导致编译错误。
if (o instanceof String s || s.length() > 4) ...
使用逻辑非运算符可以产生一些有趣的作用域效果:
if (!(o instanceof String s && s.length() > 3) return; System.out.println(s.length()); // s is in scope here
我已经看到了对变量的作用域划分方式的一些负面反馈,但是,鉴于所有作用域都是完全合乎逻辑的,因此我认为它非常有效。
已经有计划提供此功能的第二个预览版本,该版本将扩展模式匹配以与记录一起使用,并提供实现解构模式的简单方法。可以在 JEP 375中 找到更多详细信息。
有用的NullPointerException
任何编写了多行Java代码的人都将在某个时候遇到NullPointerException。未能初始化对象引用(或将其错误地显式设置为null),然后尝试使用该引用将导致引发此异常。
在简单的情况下,找出问题的原因很简单。如果我们尝试运行以下代码:
public class NullTest { List<String> list; public NullTest() { list.add("foo"); } }
错误:
Exception in thread "main" java.lang.NullPointerException at jdk14.NullTest.<init>(NullTest.java:16) at jdk14.Main.main(Main.java:15)
在JDK 14中,如果我们运行相同的代码,我们将看到类似以下内容:
Exception in thread "main" java.lang.NullPointerException: Cannot read field "c" because "a.b" is null at Prog.main(Prog.java:5)
马上我们可以看到ab是问题所在,并着手进行纠正。我敢肯定,这将使许多Java开发人员的生活更加轻松。
新的API
现在,让我们将注意力转向类库中的更改。
java.io
PrintStream有两个新方法,write(byte [] buf)和writeBytes(byte [] buf)。这些有效地做同样的事情,等效于write(buf,0,buf.length)。之所以拥有两种不同的方法,是因为将write定义为抛出IOException(但是,奇怪的是,从不抛出),而writeBytes没有。因此,选择使用哪种方法取决于您是否希望使用try-catch块包围该调用。
有一个新的注释类型,串行。它旨在用于对序列化的编译器检查。特别是,此类型的注释应应用于与序列化相关的方法和声明为可序列化的类中的字段。(它在某些方面与Override注释类似)。
java.lang
Class类为新的Record功能提供了两种方法:isRecord()和getRecordComponents()。getRecordComponents()方法返回一个RecordComponent对象数组。RecordComponent是java.lang.reflect包中的新类,它具有11种方法来检索内容,例如注释的详细信息和泛型。
Record是一个简单的新类,它重写Object的equals,hashCode和toString方法。
NullPointerException现在作为有用的NullPointerExceptions功能的一部分覆盖了Throwable中的getMessage方法。
StrictMath类具有六个新方法,这些方法补充了需要检测溢出错误时使用的现有精确方法。新方法是decrementExact,incrementExact和negateExact(所有方法都有int和long参数的两个重载版本)。
java.lang.annotation
ElementType枚举为Records添加了一个新的常量RECORD_TYPE。
java.lang.invoke
MethodHandles.Lookup类具有两个新方法:
java.lang.runtime
这是JDK 14中的新软件包,只有一个类ObjectMethods。这是记录功能的低级部分,它具有单个方法(引导程序),该方法生成对象等于,hashCode和toString方法。
java.util.text
CompactNumberFormat类具有一个新的构造函数,该构造函数为pluralRules添加了一个参数。这是一个String,表示将Count关键字(例如“ one”)与实际整数关联的多个规则。它的语法在Unicode Consortium的复数规则语法中定义。
java.util
HashSet类具有一个新方法toArray,该方法返回一个数组,其运行时组件类型为Object,包含此集合中的所有元素。
java.util.concurrent.locks
LockSupport类具有一个新方法setCurrentBlocker。LockSupport提供了暂存和取消暂存线程的功能(与不赞成使用的Thread.suspend和Thread.resume方法没有相同的问题)。现在可以设置getBlocker将返回的Object。从非公共对象调用无参数停放方法时,这很有用。
javax.lang.model.element
ElementKind枚举具有三个新常量,用于记录和模式匹配实例的特征,即BINDING_VARIABLE,RECORD和RECORD_COMPONENT。
javax.lang.model.util
该软件包提供实用程序,以协助处理程序元素和类型。通过添加记录,添加了一组新的抽象类和具体类来支持此功能。(示例是AbstractTypeVisitor14,ElementScanner14和TypeKindVisitor14)。
org.xml.sax
一种新方法已添加到SAX XML解析器的ContentHandler接口。声明方法接收XML声明的通知。在默认实现的情况下,此操作无效。
JEP 370:外部内存访问API
这是作为孵化器模块引入的,以允许更广泛的Java社区进行测试,并在其成为Java SE标准的一部分之前集成反馈。它旨在替代sun.misc.Unsafe和java.io.MappedByteBuffer。
外部存储器访问API引入了三个主要抽象:
JVM更改
我扫描了JVM规范的所有609页,但是找不到突出显示的差异。查看为记录生成的字节码会很有趣,因为在JVM级别上不需要任何特殊支持。有用的NullPointerException功能也是如此。
JDK 14确实包含一些JEP,这些JEP更改了JVM的非功能部分
其它功能
有许多与OpenJDK的不同部分相关的JEP:
如您所见,JDK 14包含了许多新功能,这些功能将使开发人员的生活更加轻松。
现在可以免费 下载OpenJDK 14 的免费 Zulu社区版本 。为什么不试试呢?