1. 概况

Oracle于2018年9月发布Java 11,而距上一次Java 10发行仅6个月时间。

Java 11是继Java 8之后的第一个LTS版本(长期支持)。 同时Oracle于2019年1月停止了对 Java8 的支持。因此,我们许多人将升级到Java 11。

本文首先介绍JDK不同版本之间的差异。然后,我们将探索Java 11引入的新功能,被删除的功能以及有哪些性能提升。

2. Oracle vs. Open JDK

Java 10是最后一个Oracle JDK的免费版本,我们无需许可证即可商业使用。 从Java 11开始,Oracle没有免费的长期支持版本(LTS)。

庆幸的是,Oracle继续提供Open JDK版本,我们可以免费下载和使用。

除了Oracle外, 还有其他Open JDK衍生版本可供我们考虑。

3. 新特性

让我们看看Java 11中新增了哪些对开发人员有用的功能。

3.1. String 新方法

Java11 String 类 新增了几个方法 : isBlank , lines , strip , stripLeading , stripTrailing , repeat

下面我们演示如何利用新方法,从多行文本中,读取strip后、非空的行字符串:

String multilineString = "Baeldung 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("Baeldung helps", "developers", "explore Java.");

新增的这些方法可以大大减少重复模板代码,降低我们对第三方库的依赖。

对于 strip 方法,它们提供了和 trim 方法类似的功能。 但具有更好的控制和Unicode支持。

3.2. File 新方法

**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. Collection 转 Array

java.util.Collection 接口新增了一个default方法 toArray ,该方法接收一个 IntFunction 参数。

通过它可以更方便地将一个 Collection 转换为类型正确的数组

List sampleList = Arrays.asList("Java", "Kotlin");
String[] sampleArray = sampleList.toArray(String[]::new);
assertThat(sampleArray).containsExactly("Java", "Kotlin");

3.4. Not Predicate 方法

Predicate 接口新增了not静态方法。我们可以使用它对当前Predicate进行取非操作(“!"),就像 negate 方法一样:

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关键字)

我们可以利用此特性将修饰符应用于局部变量,例如定义类型注解(type annotation):

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. HTTP Client

Java 9中引入的新的HTTP client(java.net.http包下),现在已得到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 嵌套访问控制(Nest Based Access Control)

** Java 11 在 JVM 中引入了嵌套的概念和相关的访问规则。 **

A nest of classes in Java implies both the outer/main class and all its nested classes:

assertThat(MainClass.class.isNestmateOf(MainClass.NestedClass.class)).isTrue();

Nested classes are linked to the NestMembers attribute, while the outer class is linked to the NestHost attribute:

assertThat(MainClass.NestedClass.class.getNestHost()).isEqualTo(MainClass.class);

JVM access rules allow access to private members between nestmates. However, in previous Java versions, the reflection API denied the same access.

Java 11 fixes this issue and provides means to query the new class file attributes using the reflection 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 文件

Java 11之前 我们需要先使用 javac 命令编译源码:

$ javac HelloWorld.java
$ java HelloWorld 
Hello Java 8!

现在 java 命令支持 直接运行源文件,而无需预编译:

$ java HelloWorld.java
Hello Java 11!

4. 性能增强

Java 11还增加了几个主要以提升性能为目的新特性:

4.1. 动态的类文件常量(Dynamic Class-File Constants)

. Java 扩展了class文件格式以支持新的常量池 —— CONSTANT_Dynamic

Loading the new constant-pool will delegate creation to a bootstrap method, just as linking an invokedynamic call site delegates linkage to a bootstrap method.

This feature enhances performances and targets language designers and compiler implementors.

4.2. 改进的 Aarch64 Intrinsics

Java 11 optimizes the existing string and array intrinsics on ARM64 or AArch64 processors. Also, new intrinsics are implemented for sin, cos, and log methods of java.lang.Math.

We use an intrinsic function like any other. However, the intrinsic function gets handled in a special way by the compiler. It leverages CPU architecture-specific assembly code to boost performance.

4.3. No-Op Garbage Collector -不回收垃圾的垃圾回收器

Java 11 引入了一个新的实验性垃圾回收器 —— Epsilon。

Epsilon 垃圾回收器不执行任何垃圾回收工作,适用于模拟内存不足错误的场景。

显然,Epsilon 不适合上线生产环境。 但是,有一些特定的用例可能会有用:

  • 性能测试
  • 内存压力测试
  • VM 接口测试
  • 存活极短的任务

要启用它,添加 -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC 参数。

4.4. 飞行记录器(Flight Recorder)

飞行记录器 (JFR) 之前是 Oracle JDK 中的一个商用产品,现已在Open JDK中开源。JFR 是一个性能分析工具,我们可以使用它从正在运行的 Java 应用程序中收集诊断和分析数据。

要开启一个时长为 120 秒的 JFR 记录,我们可以使用以下参数:

-XX:StartFlightRecording=duration=120s,settings=profile,filename=java-demo-app.jfr

JFR性能开销通常低于 1%,因此可以将它用于生产环境。记录的数据保存在.jfr文件中。

为了分析和可视化数据,我们还需要使用另一款工具 —— JDK Mission Control (JMC) 。

5. 已移除和废弃(deprecated)的模块

随着Java的不断发展,一些功能已被删除,一些功能已被废弃(deprecated)。我们应该尽快停止使用已废弃的功能。

5.1 Java EE 和 CORBA

Standalone versions of the Java EE technologies are available on third-party sites. Therefore, there is no need for Java SE to include them.

Java 9中已废弃了Java EE和CORBA模块。在Java 11中,这2个模块已被彻底删除:

  • Java API for XML-Based Web Services (java.xml.ws)
  • Java Architecture for XML Binding (java.xml.bind)
  • JavaBeans Activation Framework (java.activatio)
  • Common Annotations (java.xml.ws.annotation)
  • Common Object Request Broker Architecture (java.corba)
  • JavaTransaction API (java.transaction)

5.2 JMC 和 JavaFX

JDK Mission Control (JMC) 不再包含在JDK中,需要单独下载安装。

JavaFX 模块也是,需要单独下载。

5.3. 已废弃的模块

Java 11 废弃了下面的模块:

  • Nashorn JavaScript 引擎,包括 JJS 工具
  • Pack200 compression scheme for JAR files

6. 其他变化

最后,Java 11 还有一些重要的变化需要提及:

  • 实现了新的 ChaCha20 和 ChaCha20-Poly1305 加密算法取代不安全的RC4。
  • Support for cryptographic key agreement with Curve25519 and Curve448 replace the existing ECDH scheme
  • 升级TLS版本到1.3,提升了安全性和性能
  • 推出的一款新的低延迟垃圾回收器 —— ZGC
  • 支持 Unicode 10, 带来了更多的字符、符号和表情符号

7. 总结

本文中,我们探索了Java 11中的新特性。

我们介绍了 Oracle 和 Open JDK 之间的区别。 此外,我们还浏览了API的更改以及其他有用的开发功能,性能增强以及已删除或不建议使用的模块。

惯例,本文源码,可从GitHub上获取。