4. JDK8 新特性
参考官网: openjdk.org/projects/jd…
yaml复制代码181: Nest-Based Access Control
181: 基于嵌套的访问控制
309: Dynamic Class-File Constants
309: 动态类文件常数
315: Improve Aarch64 Intrinsics
315: 改进 Aarch64内部结构
318: Epsilon: A No-Op Garbage Collector
318: Epsilon: 一个不可操作的垃圾收集器
320: Remove the Java EE and CORBA Modules
320: 删除 JavaEE 和 CORBA 模块
321: HTTP Client (Standard)
321: HTTP 客户端(标准)
323: Local-Variable Syntax for Lambda Parameters
323: Lambda 参数的局部变量语法
324: Key Agreement with Curve25519 and Curve448
324: 与 Curve25519和 Curve448的关键协议
327: Unicode 10
328: Flight Recorder
328: 飞行记录器
329: ChaCha20 and Poly1305 Cryptographic Algorithms
329: ChaCha20和 Poly1305密码算法
330: Launch Single-File Source-Code Programs
330: 启动单文件源代码程序
331: Low-Overhead Heap Profiling
331: 低开销堆分析
332: Transport Layer Security (TLS) 1.3
332: 传输层安全(TLS)1.3
333: ZGC: A Scalable Low-Latency Garbage Collector
(Experimental)
333: ZGC: 一个可伸缩的低延迟垃圾收集器(实验)
335: Deprecate the Nashorn JavaScript Engine
335: 废弃 Nashorn JavaScript 引擎
336:
Deprecate the Pack200 Tools and API废弃 Pack200工具和 API
4.1 Lambda 参数的局部变量语法
在JDK 11及更高版本中,Lambda表达式的参数可以使用var关键字来声明局部变量。使用var关键字可以让编译器根据上下文推断参数的类型。以下是Lambda参数的局部变量语法示例:
interface MyInterface {
void myMethod(String name, int age);
}
public class Main {
public static void main(String[] args) {
MyInterface myLambda = (var name, var age) -> {
System.out.println("Name: " + name);
System.out.println("Age: " + age);
};
myLambda.myMethod("John", 25);
}
}
在上述示例中,我们使用Lambda表达式实现了MyInterface
接口的myMethod
方法。Lambda表达式的参数使用var
关键字声明为局部变量。编译器会根据上下文推断参数的类型。 请注意,Lambda参数的类型推断只适用于局部变量,而不适用于方法的参数类型、返回类型或字段类型。
4.2 HTTP 客户端(标准)
在JDK 11中,引入了标准的HTTP客户端API,用于发送HTTP请求和处理响应。这个API提供了一种原生的方式来进行HTTP通信,不再需要使用第三方库。以下是一个简单的示例:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.CompletableFuture;
public class HttpClientExample {
public static void main(String[] args) throws Exception {
// 创建HTTP客户端
HttpClient httpClient = HttpClient.newHttpClient();
// 创建HTTP请求
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/data"))
.build();
// 发送HTTP请求并异步获取响应
CompletableFuture<HttpResponse<String>> future = httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString());
// 处理响应
future.thenAccept(response -> {
int statusCode = response.statusCode();
String responseBody = response.body();
System.out.println("Status code: " + statusCode);
System.out.println("Response body: " + responseBody);
});
// 等待异步请求完成
future.join();
}
}
在上述示例中,我们首先创建一个HttpClient
对象,然后构建一个HttpRequest
对象,指定请求的URI。接下来,使用sendAsync
方法发送异步请求,并指定响应的处理方式(这里使用HttpResponse.BodyHandlers.ofString()
将响应体解析为字符串)。 通过CompletableFuture
的thenAccept
方法,我们可以处理异步请求完成后的响应。在回调函数中,我们获取响应的状态码和响应体,并进行相应的处理。 最后,我们使用future.join()
等待异步请求完成。注意,此处的异步请求是非阻塞的,可以继续执行其他操作。
4.3 新的 Collection.toArray()
在JDK 11中,Collection
接口新增了一个重载的toArray
方法,用于将集合转换为数组。该方法的签名如下:
default <T> T[] toArray(IntFunction<T[]> generator)
这个方法接受一个IntFunction<T[]>
类型的参数,该参数用于提供一个生成指定类型数组的函数。函数的输入参数是集合的大小,输出是一个新的数组。 下面是一个示例代码,演示如何使用JDK 11中的Collection.toArray
方法:
import java.util.ArrayList;
import java.util.List;
public class CollectionToArrayExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
// 使用Collection.toArray方法转换为数组
String[] array = list.toArray(String[]::new);
// 打印数组元素
for (String element : array) {
System.out.println(element);
}
}
}
在上述示例中,我们创建了一个ArrayList
对象并向其中添加一些元素。然后,我们使用toArray
方法将ArrayList
转换为String
类型的数组。注意到,我们使用了String[]::new
作为IntFunction
参数,这样就会生成一个与集合大小相同的新数组。 最终,我们遍历数组并打印每个元素,这个新的toArray
方法简化了集合到数组的转换过程,并且避免了类型转换的麻烦。
4.4 新的字符串方法
JDK 11引入了一些新的字符串方法,以提供更方便和强大的字符串操作功能。以下是一些JDK 11中新增的字符串方法:
**String.isBlank()**
:该方法用于检查字符串是否为空白字符串。它返回一个布尔值,指示字符串是否为空白。如果字符串是空白字符串(仅由空格、制表符、换行符等字符组成),则返回true
;否则返回false
。**String.strip()**
:该方法用于去除字符串的首尾空白字符。它返回一个新的字符串,其中去除了原始字符串的首尾空白字符。与trim()
方法不同的是,strip()
方法可以正确处理Unicode空白字符。**String.stripLeading()**
和**String.stripTrailing()**
:这两个方法分别用于去除字符串的前导空白字符和尾随空白字符。它们返回一个新的字符串,其中去除了原始字符串的前导或尾随空白字符。**String.lines()**
:该方法返回一个包含字符串中所有行的Stream
。它根据行终止符将字符串拆分成多个行,并返回一个Stream
,每个元素代表一行。**String.repeat(int count)**
:该方法用于重复字符串指定次数,并返回一个新的字符串。它接受一个整数参数count
,指定要重复的次数。
这些方法都是在java.lang.String
类中新增的,可以直接在字符串对象上调用。它们提供了更直观和方便的字符串操作,简化了对字符串的处理和转换。请注意,这些方法在JDK 11及更高版本中可用。
4.5 新的文件方法
JDK 11引入了一些新的文件方法,以提供更便捷和强大的文件操作功能。以下是一些JDK 11中新增的文件方法:
**Files.writeString()**
:该方法用于将字符串写入文件。它接受一个文件路径和要写入的字符串,可以指定编码格式和可选的文件选项。如果文件不存在,则创建新文件;如果文件已存在,则覆盖原有内容。**Files.readString()**
:该方法用于读取文件内容并以字符串形式返回。它接受一个文件路径,可以指定编码格式和可选的文件选项。**Files.writeStringList()**
:该方法用于将字符串列表逐行写入文件。它接受一个文件路径和字符串列表,可以指定编码格式和可选的文件选项。**Files.readStringList()**
:该方法用于逐行读取文件内容,并以字符串列表的形式返回。它接受一个文件路径,可以指定编码格式和可选的文件选项。**Files.mismatch()**
:该方法用于比较两个文件的内容。它接受两个文件路径,并返回第一个不匹配的字节的位置。如果文件完全相同,则返回-1。
这些方法都是在java.nio.file.Files
类中新增的,用于处理文件的读写和比较操作。它们提供了更便捷和高效的方式来操作文件内容。 以下是一个示例代码,演示如何使用JDK 11的新文件方法读取和写入文件:
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.List;
public class FileOperations {
public static void main(String[] args) throws Exception {
String filePath = "example.txt";
// 写入文件
String content = "Hello, world!";
Files.writeString(Path.of(filePath), content);
// 读取文件
String fileContent = Files.readString(Path.of(filePath));
System.out.println("文件内容:\n" + fileContent);
// 逐行写入文件
List<String> lines = List.of("Line 1", "Line 2", "Line 3");
Files.writeStringList(Path.of(filePath), lines, StandardOpenOption.APPEND);
// 逐行读取文件
List<String> fileLines = Files.readStringList(Path.of(filePath));
System.out.println("文件行数:" + fileLines.size());
System.out.println("文件内容:");
for (String line : fileLines) {
System.out.println(line);
}
}
}
在上述示例中,我们首先使用Files.writeString
方法将字符串写入文件。然后使用Files.readString
方法读取文件内容,并打印到控制台。 接下来,我们使用Files.writeStringList
方法逐行写入字符串列表到文件。然后使用Files.readStringList
方法逐行读取文件内容,并打印到控制台。
4.6 一个无操作垃圾收集器
JDK 11引入了一个名为"ZGC"(Z Garbage Collector)的新的垃圾收集器,它被设计为一种无操作垃圾收集器。这意味着它在大部分情况下几乎不会对应用程序的执行造成明显的停顿 ZGC是一种低延迟的垃圾收集器,旨在实现非常短暂的停顿时间。它的目标是保持最大15毫秒的停顿时间,并限制不超过10%的吞吐量损失。这使得ZGC适合那些对低延迟和高吞吐量要求都很高的应用程序。 ZGC使用了一些创新的技术来实现其目标。它使用了一种称为"Region"的内存布局,将堆内存划分为一系列大小固定的区域,使得垃圾收集可以在不停止整个应用程序的情况下并发进行。此外,ZGC还使用了写屏障技术来跟踪对象的引用变化,并在后台处理未访问的对象。 需要注意的是,ZGC在JDK 11中被标记为实验性特性,并且默认情况下并不启用。要使用ZGC收集器,需要通过JVM参数显式地启用。可以使用以下参数启用ZGC收集器:
-XX:+UseZGC
使用ZGC收集器的示例如下:
public class ZGCExample {
public static void main(String[] args) {
// 设置ZGC作为垃圾收集器
System.setProperty("java.vm.useZGC", "true");
// 应用程序代码...
}
}
需要注意的是,ZGC仅适用于支持64位操作系统和64位JVM的平台。并且在某些情况下,它可能与一些JVM选项不兼容,例如启用了某些特定的实验性特性。
4.7 启动单文件源代码程序
JDK 11引入了一项新功能,允许直接启动单个源代码文件而无需先将其编译为字节码文件。这个功能称为"单文件源代码程序"(Single-File Source-Code Programs)。 要在JDK 11中启动单文件源代码程序,可以使用以下命令:
java <options> <source-file>.java
其中,<options>
是可选的JVM选项,<source-file>.java
是要执行的源代码文件。 以下是一个示例,演示如何使用JDK 11启动单文件源代码程序:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
保存上述代码为HelloWorld.java
文件。 然后,通过以下命令运行该源代码文件:
java HelloWorld.java
注意,在执行单文件源代码程序时,JDK 11会在内部将源代码文件编译为字节码,并在运行时执行。这使得我们能够更方便地运行和测试简单的Java程序,而无需事先编译为.class文件。 需要注意的是,单文件源代码程序主要适用于简单的小型程序或测试目的。对于复杂的项目,仍然建议将源代码编译为字节码文件,并使用传统的方式执行。
4.8 基于嵌套的访问控制
JDK 11引入了一项新的语言特性,即基于嵌套的访问控制(Nested Access Control)。这个特性旨在提供更细粒度的访问控制机制,以保护类的内部结构,并更好地支持模块化开发。 在传统的Java访问控制中,类的成员(字段、方法、内部类等)可以被声明为public
、protected
、private
或默认(不写访问修饰符)。这些修饰符控制着类的成员在不同上下文中的可见性。 而基于嵌套的访问控制引入了两个新的访问修饰符:private
和protected
的嵌套形式。这些修饰符用于限制对嵌套类的访问,使得只有特定的外部类可以访问其嵌套类的成员。 具体而言,以下是基于嵌套的访问控制修饰符的规则:
**private**
的嵌套形式(private nested):内部类声明为private
的嵌套形式时,只有外部类可以访问该嵌套类。**protected**
的嵌套形式(protected nested):内部类声明为protected
的嵌套形式时,只有外部类及其子类可以访问该嵌套类。
这些新的访问修饰符对于模块化开发非常有用,可以更好地封装类的内部结构,避免不必要的访问和依赖关系。 以下是一个示例,展示了基于嵌套的访问控制的使用:
public class OuterClass {
private int privateField;
private static class PrivateNestedClass {
private void privateMethod() {
OuterClass outer = new OuterClass();
outer.privateField = 10;
}
}
protected static class ProtectedNestedClass {
protected void protectedMethod() {
OuterClass outer = new OuterClass();
outer.privateField = 20;
}
}
public static void main(String[] args) {
PrivateNestedClass privateNested = new PrivateNestedClass();
privateNested.privateMethod();
ProtectedNestedClass protectedNested = new ProtectedNestedClass();
protectedNested.protectedMethod();
}
}
在上述示例中,PrivateNestedClass
是一个私有的嵌套类,只有OuterClass
内部可以访问它。ProtectedNestedClass
是一个受保护的嵌套类,只有OuterClass
及其子类可以访问它。 在main
方法中,我们可以实例化并调用这些嵌套类的方法,因为它们的访问限制在其声明的上下文中是有效的。 需要注意的是,基于嵌套的访问控制修饰符只适用于嵌套类,而不适用于顶级类(即没有外部类的类)。此外,仍然可以使用传统的访问修饰符(public
、protected
、private
和默认)来控制顶级类的访问性。
4.9 Java 飞行记录器
JDK 11引入了一个名为"Java飞行记录器"(Java Flight Recorder,JFR)的功能,它是一个事件记录和分析引擎,用于在运行时收集和分析Java应用程序的运行数据。 Java飞行记录器可以捕获各种事件,包括方法调用、垃圾收集、线程活动、I/O操作等。它还可以收集各种度量指标,如CPU使用率、内存使用量、线程数量等。这些事件和度量指标可以用于分析和优化应用程序的性能、诊断问题和进行故障排除。 使用Java飞行记录器需要以下步骤:
- 启用Java飞行记录器:要使用Java飞行记录器,首先需要在JVM参数中启用它。可以使用以下参数启用JFR:
-XX:+UnlockCommercialFeatures -XX:+FlightRecorder
注意,Java飞行记录器属于商业特性,在某些Java发行版中可能需要适当的许可证。
- 配置和启动飞行记录器:一旦启用了Java飞行记录器,你可以使用命令行工具(如
jcmd
、jfr
)或编程方式来配置和启动飞行记录器。你可以指定要记录的事件类型、持续时间等。 - 收集和分析记录数据:在应用程序运行期间,Java飞行记录器将会收集指定的事件和度量指标。收集的数据可以保存到文件中。然后,你可以使用Java Mission Control(JMC)或其他工具来加载和分析这些记录文件,以获得有关应用程序性能和行为的详细信息。
Java飞行记录器提供了强大的性能分析和故障排除能力,能够帮助开发人员识别和解决应用程序中的性能问题和异常情况。它是JDK 11中一个重要的调试和优化工具。
4.10 低开销的堆分析
在JDK 11中,引入了一项名为"低开销的堆分析"(Low Overhead Heap Profiling)的功能,它允许在应用程序运行时收集堆分析数据,以便更好地理解和调试内存使用情况。 传统的堆分析工具通常会对应用程序的内存进行全面的快照,以获取详细的对象分配和引用关系信息。然而,这种全面的堆快照收集过程可能会对应用程序的性能产生较大的开销,特别是在大型应用程序中。 低开销的堆分析通过减少采样频率和记录粒度,以及使用一些技术手段来减少开销,从而提供了一种更轻量级的堆分析方法。它可以在应用程序运行时进行堆分析,对内存使用情况进行采样,并生成堆分析报告。 要使用低开销的堆分析功能,可以使用以下JVM参数:
-XX:StartFlightRecording=heap=low
这将启用低开销的堆分析,并将堆分析数据记录到默认的JFR文件中。 然后,可以使用Java Mission Control(JMC)或其他JFR分析工具加载和分析生成的JFR文件,以获得有关应用程序内存使用的详细信息。JFR分析工具提供了堆分配热点、对象分布、对象生命周期等信息,帮助开发人员识别内存泄漏、过度分配和其他内存相关问题。 需要注意的是,低开销的堆分析是一种近似的分析方法,它可能会在某些情况下丢失一些细节信息。因此,在某些情况下,仍然建议使用传统的全面堆分析方法来获取更准确的堆快照。
4.11 从 Oracle JDK 中移除 JavaFX
从 Java 11 开始,JavaFX(以及相关的 javapackager 工具)不再随 JDK 一起提供。相反,我们可以从 JavaFX 主页将其作为单独的 SDK 下载。
4.12 删除模块
JEP 320 从 JDK 中删除了以下模块:
- java.xml.ws (JAX-WS)
- java.xml.bind (JAXB)
- java.activation (JAF)
- java.xml.ws.annotation(通用注解)
- java.corba (CORBA)
- java.transaction (JTA)
- java.se.ee(前面提到的六个模块的聚合器模块)
- jdk.xml.ws(JAX-WS 工具)
- jdk.xml.bind(JAXB 工具)
其他请参考官方文档