Java 11中的新功能
1. 概述
甲骨文于 2018 年 9 月发布了 Java 11,仅比其前身版本 10 晚了 6 个月。 **Java 11 是 Java 8 之后的第一个长期支持 (LTS) 版本。**甲骨文也在 2019 年 1 月停止支持Java 8。因此,我们中的很多人将升级到 Java 11。 在本教程中,我们将看看我们选择 Java 11 JDK 的选项。然后我们将探索 Java 11 中引入的新特性、删除的特性和性能增强。
2. Oracle 与 Open JDK
Java 10 是最后一个免费的 Oracle JDK 版本,我们可以在没有许可证的情况下将其用于商业用途。从 Java 11 开始,Oracle 不再提供免费的长期支持 (LTS)。 值得庆幸的是,Oracle 继续提供Open JDK 版本,我们可以免费下载和使用。
除了 Oracle,我们还可以考虑其他 Open JDK 提供商。
3. 开发者特色
让我们来看看对通用 API 的更改,以及对开发人员有用的其他一些功能。
3.1. 新的字符串方法
Java 11向String类添加了一些新方法 :isBlank、lines、strip、stripLeading、stripTrailing和repeat。 让我们看看如何使用新方法从多行字符串中提取非空白、剥离的行:
String multilineString = "Blogdemo helps \n \n developers \n explore Java.";
List<String> lines = multilineString.lines()
.filter(line -> !line.isBlank())
.map(String::strip)
.collect(Collectors.toList());
assertThat(lines).containsExactly("Blogdemo helps", "developers", "explore Java.");
这些方法可以减少涉及操作字符串对象的样板数量,并使我们不必导入库。
对于strip方法,它们提供与更熟悉的trim方法类似的功能;但是,具有更好的控制和 Unicode 支持。
3.2. 新文件方法
此外,现在可以更轻松地从文件中读取和写入String。 我们可以使用Files类中新的readString和writeString静态方法:**
Path filePath = Files.writeString(Files.createTempFile(tempDir, "demo", ".txt"), "Sample text");
String fileContent = Files.readString(filePath);
assertThat(fileContent).isEqualTo("Sample text");
3.3. 集合到数组
java.util.Collection接口包含一个新的默认toArray方法,**它接受一个IntFunction参数。 这使得从集合中创建正确类型的数组变得更加容易:
List sampleList = Arrays.asList("Java", "Kotlin");
String[] sampleArray = sampleList.toArray(String[]::new);
assertThat(sampleArray).containsExactly("Java", "Kotlin");
3.4. Not 谓词方法
Predicate接口中添加了静态not方法 。我们可以使用它来否定现有谓词,就像否定方法一样:
List<String> sampleList = Arrays.asList("Java", "\n \n", "Kotlin", " ");
List withoutBlanks = sampleList.stream()
.filter(Predicate.not(String::isBlank))
.collect(Collectors.toList());
assertThat(withoutBlanks).containsExactly("Java", "Kotlin");
虽然not(isBlank)比isBlank.negate()读起来更自然,但最大的优势是我们还可以将not与方法引用一起使用,例如not(String:isBlank)。
3.5. Lambda 的局部变量语法
Java 11 添加了对在 lambda 参数中使用局部变量语法 (var关键字)的支持。 我们可以利用此功能将修饰符应用于我们的局部变量,例如定义类型注释:
List<String> sampleList = Arrays.asList("Java", "Kotlin");
String resultString = sampleList.stream()
.map((@Nonnull var x) -> x.toUpperCase())
.collect(Collectors.joining(", "));
assertThat(resultString).isEqualTo("JAVA, KOTLIN");
3.6. 客户端
java.net.http包中的新HTTP 客户端 是在 Java 9 中引入的。它现在已成为 Java 11 中的标准功能。 新的 HTTP API 提高了整体性能并同时支持 HTTP/1.1 和 HTTP/2:
HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(20))
.build();
HttpRequest httpRequest = HttpRequest.newBuilder()
.GET()
.uri(URI.create("http://localhost:" + port))
.build();
HttpResponse httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
assertThat(httpResponse.body()).isEqualTo("Hello from the server!");
3.7. 基于嵌套的访问控制
Java 11在 JVM 中引入了nestmates 的概念和相关的访问规则。 Java 中的类嵌套意味着外部/主类及其所有嵌套类:
assertThat(MainClass.class.isNestmateOf(MainClass.NestedClass.class)).isTrue();
嵌套类链接到NestMembers属性,而外部类链接到 NestHost属性:
assertThat(MainClass.NestedClass.class.getNestHost()).isEqualTo(MainClass.class);
JVM 访问规则允许 nestmates 之间访问私有成员;然而,在以前的 Java 版本中,反射 API 拒绝了相同的访问。 Java 11 修复了这个问题并提供了使用反射 API 查询新类文件属性的方法:
Set<String> nestedMembers = Arrays.stream(MainClass.NestedClass.class.getNestMembers())
.map(Class::getName)
.collect(Collectors.toSet());
assertThat(nestedMembers).contains(MainClass.class.getName(), MainClass.NestedClass.class.getName());
3.8. 运行 Java 文件
此版本的一个主要变化是我们不再需要显式地使用*javac编译 Java 源文件:***
$ javac HelloWorld.java
$ java HelloWorld
Hello Java 8!
相反,我们可以使用java 命令直接运行该文件 :
$ java HelloWorld.java
Hello Java 11!
4. 性能提升
现在让我们来看看一些主要目的是提高性能的新特性。
4.1. 动态类文件常量
扩展了 Java 类文件格式以支持名为CONSTANT_Dynamic的新常量池形式。 加载新的常量池会将创建委托给引导方法,就像链接invokedynamic调用站点将链接委托给引导方法一样。
此功能可增强性能并面向语言设计者和编译器实现者。
4.2. 改进的 Aarch64 内部函数
Java 11 优化了 ARM64 或 AArch64 处理器上现有的字符串和数组内在函数。此外,为java.lang.Math的**sin、cos和log方法实现了新的内部函数。 我们像其他任何函数一样使用内在函数;但是,内部函数由编译器以特殊方式处理。它利用特定于 CPU 架构的汇编代码来提高性能。
4.3. 无操作垃圾收集器
一个名为 Epsilon 的新垃圾收集器作为一项实验性功能可用于 Java 11。 它被称为 No-Op(无操作),因为它分配内存但实际上并不收集任何垃圾。因此,Epsilon 适用于模拟内存不足错误。 显然,Epsilon 不适合典型的生产 Java 应用程序;但是,有一些特定的用例可能有用:
- 性能测试
- 内存压力测试
- VM接口测试和
- 极短命的工作
为了启用它,请使用*-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC* 标志。
4.4. 飞行记录器
Java Flight Recorder (JFR) 现在在 Open JDK 中开源,而它曾经是 Oracle JDK 中的商业产品。JFR 是一个分析工具,我们可以使用它从正在运行的 Java 应用程序收集诊断和分析数据。
要开始 120 秒的 JFR 记录,我们可以使用以下参数:
-XX:StartFlightRecording=duration=120s,settings=profile,filename=java-demo-app.jfr
我们可以在生产中使用 JFR,因为它的性能开销通常低于 1%。一旦时间过去,我们就可以访问保存在 JFR 文件中的记录数据;然而,为了分析和可视化数据,我们需要使用另一种称为JDK Mission Control (JMC) 的工具。
5. 删除和弃用的模块
随着 Java 的发展,我们不能再使用任何已删除的功能,并且应该停止使用任何已弃用的功能。让我们快速浏览一下最著名的。
5.1. Java EE 和 CORBA
Java EE 技术的独立版本可在第三方站点上获得;因此,Java SE 不需要包含它们。 Java 9 已经弃用了选定的 Java EE 和 CORBA 模块。在版本 11 中,它现已完全删除:
- 用于基于 XML 的 Web 服务的 Java API (java.xml.ws )
- XML 绑定的 Java 体系结构*(java.xml.bind* )
- JavaBeans 激活框架*(java.activation* )
- 通用注释*(java.xml.ws.annotation* )
- 通用对象请求代理架构*(java.corba)*
- JavaTransaction API (java.transaction )
5.2. JMC 和 JavaFX
JDK 任务控制 (JMC) 不再包含在 JDK 中。JMC 的独立版本现在可以单独下载。 JavaFX 模块也是如此;JavaFX 将作为 JDK 之外的一组独立模块提供。
5.3. 弃用的模块
此外,Java 11 弃用了以下模块:
- Nashorn JavaScript 引擎,包括 JJS 工具
- JAR 文件的 Pack200 压缩方案
6. 杂项变更
Java 11 引入了一些重要的更改:
- 新的 ChaCha20 和 ChaCha20-Poly1305 密码实现取代了不安全的 RC4 流密码
- 支持使用 Curve25519 和 Curve448 替换现有 ECDH 方案的密钥协议
- 升级到 1.3 版的传输层安全性 (TLS) 带来了安全性和性能改进
- 引入了低延迟垃圾收集器 ZGC,作为具有低暂停时间的实验性功能
- 对 Unicode 10 的支持带来更多字符、符号和表情符号