我们已经习惯了每六个月就会出现一个新的 JDK 版本。到目前为止,这种做法已经证明了自己的合理性,一些开发者担心自己跟不上更新的担忧是徒劳的:六个月的变化很少,而且不像以前那样具有全球性。嗯,新手程序员可能根本没有注意到这项创新。 然而,未来的软件开发人员最好能够跟上创新的步伐。在本文中,我们将按照传统方式描述已接受的扩展提案 (JEP)。Java 13 仅包含 5 个 JEP 和 76 个新的核心库元素(其中几乎一半是 java.io 包的简单添加)。
JEP 355:文本块(预览)
让我们从更改语言的语法开始。其中最重要的是文本块。它们允许您避免转义字符并了解如何格式化字符串。您可能还记得JDK 12 不包含用于处理字符串文字的预期原始字符串文字 (JEP 326) 功能。在 Java 13 中,它被 JEP 355 及其文本块取代。您可能还记得,在 Java 中,字符串用双引号括起来。这很好,但问题是一行不能占用源文件的多行(为了避免与 Java 行混淆,这里我们将文件行称为“行”)。好吧,让我们来看看,例如,\n
如果需要中断,或者连接多行表达式,则使用符号。结果不太好!嵌入 HTML、XML、SQL 或 JSON 片段的文本文字尤其麻烦。所有这些转义、串联和手动编辑使代码编写起来不方便且难以阅读。文本块试图解决这个问题。它们以呃...开头并以三个双引号结尾(我知道,这听起来不太好)。引号之间的所有内容都被解释为行的一部分,包括换行符。文本块的使用方式与标准文本文字完全相同,Java 将以相同的方式编译代码。起始引号后面必须跟有行分隔符;文本块不能在一行中使用,因此代码
String smallBlock = """Only one line""";
会导致以下错误:
TextBlock.java:3: error: illegal text block open delimiter sequence, missing line terminator
String smallBlock = """Text Block""";
^
TextBlock.java:3: error: illegal text block open delimiter sequence, missing line terminator
String smallBlock = """Text Block""";
^
现在可以像这样编写一个简单的 HTML 片段:
String htmlBlock = """
<html>
<body>
<p>CodeGym Web page</p>
</body>
<html>
""";
让我们提一下使用文本块时最好注意的一些微妙之处。事实证明,结束引号的位置很重要:它决定如何处理偶尔出现的空白。在上面的示例中,结束引号与 HTML 文本的缩进对齐。在这种情况下,编译器将删除缩进空格,结果我们将得到如下行:
<html>
<body>
<p>My web page</p>
</body>
</html>
笔记:这样的行将在行尾包含换行符。如果不需要,可以将右引号“””直接放在</html>标签之后。如果我们将收盘价移近左边距,这将改变删除的缩进量。如果我们将它们向左移动两个空格,我们就会为每行添加两个空格以进行缩进。移动到左边缘将导致保留所有填充。将引号进一步向右移动将不会产生任何效果,并且不会添加任何更多缩进。文本块作为预览功能包含在 JDK 13 中。这意味着它们尚未包含在相应的 Java 语言规范中。也就是说,目前尚不清楚该功能是否会成为该语言的永久组成部分,或者只是这里的一个客人。目前,开发人员可以测试该功能并发表意见。文本块的命运将取决于它:该功能可以改进,如果您不喜欢它,则可以将其完全删除。如果您想在实践中尝试文本块,请记住必须显式包含预览功能才能编译和运行。汇编:
javac --enable-preview --release 13 TextBlock.java
要运行该应用程序,您需要启用预览功能:
java --enable-preview TextBlock
该类String
具有三个新方法来补充此语言更改:
formatted()
:使用字符串本身作为格式字符串来格式化字符串。相当于挑战format(this, args)
stripIndent()
:从字符串中删除随机空格。如果您正在读取多行字符串并希望应用与显式声明相同的空白排除,则这非常有用。translateEscapes()
:返回带有转义序列(例如\ r
)的字符串,并转换为适当的 Unicode 值。
@PreviewFeature
会有助于解决这种情况,但它尚未包含在 JDK 中(尽管它很可能会出现在 JDK 14 中)。
JEP 354:开关表达式(预览)
Java 12 引入了一种使用 switch 语句编写表达式的新形式的提案 - JEP 325。事实证明,这是第一个预览功能,它的命运证明向用户提交提案是一个好主意。在 JDK 12 之前,switch
它只能用作执行操作但不返回结果的语句。但在 Java 12 中,它允许将其用作switch
返回可分配给变量的结果的表达式。中 case 语句的语法还有其他更改switch
。让我们看一下 JEP 中的示例来了解其工作原理。
int numberOfLetters;
switch(dayOfWeek) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numberOfLetter = 6;
break;
case TUESDAY
numberOfLetter = 7;
break;
case THURSDAY
case SATURDAY
numberOfLetter = 8;
break;
case WEDNESDAY
numberOfLetter = 9;
break;
default:
throw new IllegalStateException("Huh?: " + day);
}
在这个例子中,我们使用 valuedayOfWeek
将值赋给numberOfLetters
。由于操作人员工作的特殊性switch
,这段代码并不是最漂亮的,而且很容易出错。首先,如果我们忘记将语句应用于break
每组案例标签,我们将默认使用下一组案例标签。这可能会导致难以发现的错误。其次,我们必须定义每组案例标签。如果我们忘记了,那么我们当然会得到一个编译器错误,但这个选项也不是理想的。我们的代码也非常冗长,因为每个值都dayOfWeek
必须有自己的 case 标签。使用新语法,我们可以获得更清晰且不易出错的代码:
int numberOfLetters = switch (dayOfWeek) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
default -> throw new IllegalStateException("Huh?: " + day);
};
现在我们只需要进行一次赋值(从表达式的返回switch
值),并且可以使用逗号分隔的列表作为 case 标签。而且,由于我们不使用运算符break
,因此我们消除了与之相关的问题。表达式语法switch
允许我们使用旧式语法,因此在 JDK 12 中我们可以这样写:
int numberOfLetters = switch (dayOfWeek) {
case MONDAY:
case FRIDAY:
case SUNDAY:
break 6;
case TUESDAY
break 7;
case THURSDAY
case SATURDAY
break 8;
case WEDNESDAY
break 9;
default:
throw new IllegalStateException("Huh?: " + day);
};
根据 Java 社区的说法,使用重载break
来指定返回值可能会令人困惑。Java 语言还允许您将break
(and continue
) 与标签一起使用,如无条件跳转运算符goto
。JEP 354 改变了这种用法break
,因此在 Java 13 中我们的代码略有变化:
int numberOfLetters = switch (dayOfWeek) {
case MONDAY:
case FRIDAY:
case SUNDAY:
yield 6;
case TUESDAY
yield 7;
case THURSDAY
case SATURDAY
yield 8;
case WEDNESDAY
yield 9;
default:
throw new IllegalStateException("Huh?: " + day);
};
接下来的三个 JEP 与 Java 虚拟机相关。
JEP 350动态 CDS 存档
此扩展允许您在 Java 应用程序执行结束时动态归档类。CDS 或类数据共享允许您将启动时启动的所有类打包到一个特殊的存档中class data sharing
,默认情况下使用这些相同类的列表。这会显着加快应用程序的启动速度并节省 RAM。以前,使用 AppCDS 是一个多步骤过程,涉及创建相关类的列表并使用该列表创建将用于后续运行的存档。现在所需要做的就是使用 -XX: 标志启动应用程序,ArchiveClassesAtExit
指示将写入存档的位置。通过这种方法,应用程序正常停止后,类会自动打包到存档中。
JEP 351 ZGC:取消提交未使用的内存
一年前,JDK 11引入了 ZGC,这是一种实验性、可扩展、低延迟的垃圾收集器。起初,ZGC 的行为相当奇怪:它不允许将内存返回给操作系统,即使不再需要它。对于某些环境,例如容器,资源同时被多个服务使用,这可能会限制系统的可扩展性和效率。ZGC 堆由所谓的 ZPage 组成。当 ZPage 在垃圾收集周期期间被清除时,它们将返回到 ZPageCache。此缓存中的 ZPage 按最近使用的时间排序。在Java 13中,ZGC会将被识别为长时间未使用的页面返回给操作系统。这样它们就可以被其他进程重用。JEP 353重新实现旧版 Socket API
两个 API 实现仍然java.net.Socket
是JDK 1.0。java.net.ServerSocket
在此以及所有后续 JDK 中,这些 API 的实现使用了多种技术(例如使用线程堆栈作为 I/O 缓冲区),这使得它们不灵活且难以维护。为了解决这个问题,JDK 13中提供了新的实现NioSocketImpl
。它不再需要本机代码,从而更容易移植到不同的平台。该类还使用现有的缓冲区高速缓存机制(避免为此目的使用线程堆栈)和锁定java.util.concurrent
而不是同步方法。这将简化与Project Loom光纤的集成。
新 API
我们之前提到,Java 13 在基类库中包含 76 个新 API。它们涵盖以下领域:- Unicode 支持更新。
String
三种支持文本块的新方法(请参阅上面的 JEP 255 描述)。- 类
java.nio
现在具有绝对(而不是相对)get
和设置方法。它们与抽象基类一样,包含用于检索部分缓冲区的 Buffer
方法。slice()
force()
该类方法MappedByteBuffer
强制将缓冲区部分写入其后备存储。nio.FileSystem
添加了三个新的重载形式,newFileSystem()
用于访问作为文件系统的文件内容。- 一种新的有趣的方法出现
javax.annotation.processing.ProcessingEnvironment
了。isPreviewEnabled()
。它会告诉您是否启用了预览功能。这很有趣,因为上面提到的注释@PreviewFeature
要等到 JDK 14 发布后才可用。 DocumentBuilderFactory
并SAXParserFactory
获得javax.xml.parsers
三种用于创建命名空间感知实例的新方法。
GO TO FULL VERSION