6. JDK13 新特性
参考官网:
350:
Dynamic CDS Archives动态 CDS 存档
351:
ZGC: Uncommit Unused Memory取消未使用内存
353:
Reimplement the Legacy Socket API重新实现遗留套接字 API
354:
Switch Expressions (Preview)开关表达式(预览)
355:
Text Blocks (Preview)文本块(预览)
6.1 动态CDS归档(Dynamic CDS Archiving)
在JDK 13中,引入了一项名为动态CDS归档(Dynamic CDS Archiving)的新功能。CDS(Class Data Sharing)是一种技术,它允许将类的元数据和字节码预先加载到共享归档文件中,以提高应用程序的启动时间和内存占用。动态CDS归档进一步扩展了CDS的能力,使得在应用程序运行时可以动态地创建和更新CDS归档。 动态CDS归档的主要优势在于,它允许在应用程序运行时收集和记录正在使用的类和库,并将它们添加到已存在的CDS归档中,从而实现动态的类共享。这样,在下次启动应用程序时,可以使用包含动态更新的CDS归档,进一步加速应用程序的启动。 以下是使用动态CDS归档的一般步骤:
- 使用JDK 13构建应用程序,并确保启用CDS。可以通过使用以下参数来启用CDS:
-XX:ArchiveClassesAtExit=<archive-file>
。 - 运行应用程序,让它进行正常操作。这将导致动态CDS归档文件被创建。
- 在下次启动应用程序时,使用以下参数来启用CDS并指定先前创建的动态CDS归档文件:
-XX:SharedArchiveFile=<archive-file>
。
通过这种方式,应用程序可以利用先前收集的动态CDS归档文件,从而加快启动时间和减少内存消耗。 需要注意的是,动态CDS归档功能在JDK 13中是作为实验性功能引入的。因此,在使用时应谨慎评估其在特定应用程序和环境中的效果,并确保遵循官方文档和最佳实践。
6.2 重新实现遗留套接字 API
java.net.Socket和java.net.ServerSocket API将所有套接字操作委托给java.net.SocketImpl,这是自JDK 1.0起已经存在的服务提供程序接口(SPI)机制。内置的实现称为“普通”实现,由非公开的PlainSocketImpl通过支持类SocketInputStream和SocketOutputStream实施。 PlainSocketImpl由其他两个JDK内部实现扩展,这些实现支持通过SOCKS和HTTP代理服务器的连接。默认情况下,使用基于SOCKS的SocketImpl创建Socket和ServerSocket(有时是延迟的)。在ServerSocket的情况下,使用SOCKS实现是一个古怪的事情,可以追溯到对JDK 1.4中的代理服务器连接的实验性(并且自从删除以来)支持。 新的实现NioSocketImpl替代了PlainSocketImpl。它被开发为易于维护和调试。它与新I / O(NIO)实现共享相同的JDK内部基础结构,因此不需要自己的本机代码。它与现有的缓冲区高速缓存机制集成在一起,因此不需要将线程堆栈用于I / O。它使用java.util.concurrent锁而不是同步方法,以便将来可以在fibers上很好地使用。在JDK 11中,大多数NIO SocketChannel和其他SelectableChannel实现都是在实现相同目标的情况下重新实现的。
6.3 Switch表达式
在JDK 13中,Switch表达式引入了一些新的语法和功能,使得在Switch语句中编写更简洁和灵活的代码成为可能。下面是一些JDK 13中Switch表达式的示例:
- 简单的Switch表达式:
int day = 3;
String dayName = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
default -> "Invalid day";
};
System.out.println(dayName); // 输出: Wednesday
在这个例子中,我们使用Switch表达式根据给定的day
值返回对应的星期几名称。
- 表达式和语句的组合:
int day = 5;
String dayType = switch (day) {
case 1, 2, 3, 4, 5 -> {
yield "Weekday"; // 使用yield返回一个值
}
case 6, 7 -> {
System.out.println("It's a weekend!"); // 执行语句
yield "Weekend";
}
default -> {
yield "Invalid day";
}
};
System.out.println(dayType); // 输出: Weekend
在这个例子中,我们根据给定的day
值返回对应的日期类型。如果是工作日(1-5),我们使用yield
返回一个字符串值。如果是周末(6-7),我们首先打印一条消息,然后返回一个字符串值。
- 表达式的返回类型推断:
String dayName = switch (getDayOfWeek()) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
default -> "Invalid day";
};
System.out.println(dayName);
在这个例子中,getDayOfWeek()
方法返回一个整数表示星期几。在Switch表达式中,我们根据这个返回值进行匹配,并返回对应的星期几名称。注意,我们没有显式地指定Switch表达式的返回类型,而是使用类型推断,编译器会自动推断返回类型为String
。 这些示例展示了JDK 13中Switch表达式的一些用法。Switch表达式的引入使得编写简洁、灵活的条件分支逻辑变得更加容易。
6.4 文本块
在JDK 13中,引入了文本块(Text Blocks)功能,它提供了一种更直观和易读的方式来定义多行字符串。文本块使得在Java代码中编写包含换行符和缩进的长字符串变得更加方便。下面是一些JDK 13中文本块的示例:
- 基本的文本块:
String htmlContent = """
<html>
<body>
<h1>Hello, JDK 13!</h1>
</body>
</html>
""";
在这个例子中,我们使用文本块定义了一个包含HTML标记的字符串。文本块使用三个双引号(""")作为起始和结束标记,使得可以在字符串中包含多行内容,并且保留了换行符和缩进。
- 转义字符的处理:
String message = """
This is a multiline string \
with line continuation.
""";
在这个例子中,我们使用文本块定义了一个包含转义字符的多行字符串。在文本块中,使用反斜杠(\)来表示行连接符,可以在多行字符串中实现行的延续。
- 引号的处理:
String quote = """
She said, "Java is awesome!"
""";
在这个例子中,我们使用文本块定义了一个包含引号的多行字符串。在文本块中,可以直接使用引号而无需进行转义。
- 保留缩进的控制:
String indentedString = """
This is an indented string.
It has nested indentation.
""";
在这个例子中,我们使用文本块定义了一个具有保留缩进的字符串。文本块中的每行会保留与起始双引号的缩进级别一致的空格。
6.5 ZGC改进
在JDK 13中,ZGC(Z Garbage Collector)垃圾收集器进行了一些改进,以进一步降低垃圾收集的停顿时间并提高吞吐量。以下是一些JDK 13中ZGC的改进:
- 停顿时间优化:ZGC通过引入更多并发操作来减少垃圾收集的停顿时间。JDK 13对ZGC进行了一些优化,以减少并发标记和并发整理阶段的停顿时间。这意味着应用程序在运行时不会因为垃圾收集而出现明显的停顿。
- 吞吐量改进:ZGC的目标之一是在减少停顿时间的同时提高吞吐量。JDK 13引入了一些吞吐量方面的改进,以提高应用程序的整体性能。这些改进包括并发垃圾收集的并行处理,以及更高效的内存分配和回收策略。
- 栈上分配:ZGC在JDK 13中引入了栈上分配(Stack Allocation)的优化。栈上分配是一种优化技术,将一些短暂的对象分配到线程的栈上,而不是堆上。这样可以减少垃圾收集的工作量,并且可以更快地回收这些短暂对象。
- 并发Class Unloading:JDK 13中的ZGC引入了并发类卸载(Concurrent Class Unloading)的功能。这意味着当类不再使用时,可以在应用程序运行时卸载类,而无需停止应用程序的执行。这有助于减少内存占用,并提高应用程序的可伸缩性。
这些改进使得ZGC在JDK 13中更加适用于处理大型堆内存和具有低延迟要求的应用程序。然而,需要注意的是ZGC并非适用于所有场景,具体的垃圾收集器选择应该根据应用程序的特点和需求进行评估和选择。 请注意,ZGC是在JDK 11中首次引入的,而在JDK 13中进行了一些改进和优化。