# ☕ Java 11 新特性详解

# 一、核心概念与概述

# 1. Java 11 简介

Java 11 是 Java 编程语言的一个长期支持(LTS)版本,于 2018 年 9 月发布。作为继 Java 8 之后的第二个 LTS 版本,Java 11 带来了许多重要的特性和改进,包括性能优化、新的 API、工具增强等。

Java 11 的主要特性包括:

  • 局部变量类型推断增强
  • HTTP Client API 标准化
  • 新的字符串处理方法
  • 集合 API 增强
  • ZGC 垃圾收集器
  • Epsilon 无操作垃圾收集器
  • 飞行记录器(JFR)
  • 启动单文件源代码程序
  • 移除 Java EE 和 CORBA 模块
  • 支持 TLS 1.3

# 2. 为什么需要 Java 11?

Java 11 是一个重要的长期支持版本,提供了更好的性能、安全性和稳定性。它引入了许多实用的特性,简化了开发工作,同时移除了过时的组件,使 Java 平台更加现代化。

Java 11 的特性解决了以下问题:

  • 提高应用程序的启动速度和响应性能
  • 简化 HTTP 客户端开发
  • 提供更高效的垃圾回收机制
  • 增强字符串和集合的操作能力
  • 提升安全性和 TLS 支持
  • 优化 Java 平台的模块化结构

# 二、核心特性详解

# 1. 局部变量类型推断增强

Java 11 扩展了 Java 10 中引入的局部变量类型推断(var 关键字),使其可以用于 lambda 表达式的参数声明,这在某些情况下可以提高代码的可读性。

示例:

// Java 10 中 var 的使用
var list = new ArrayList<String>();
var stream = list.stream();

// Java 11 中 var 在 lambda 表达式中的使用
(var x, var y) -> x + y;

// 在使用泛型的情况下特别有用
Function<List<String>, Map<String, Integer>> countWords = (var words) -> {
    var counts = new HashMap<String, Integer>();
    for (var word : words) {
        counts.put(word, counts.getOrDefault(word, 0) + 1);
    }
    return counts;
};

# 2. HTTP Client API 标准化

Java 11 将 Java 9 中引入的 HTTP/2 客户端 API 从孵化器阶段提升到正式版,提供了一个现代化的 HTTP 客户端 API,支持 HTTP/1.1 和 HTTP/2。

示例:

// 创建 HTTP 客户端
HttpClient client = HttpClient.newHttpClient();

// 创建 HTTP 请求
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com/data"))
    .header("Accept", "application/json")
    .GET()
    .build();

// 发送同步请求
HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());

// 发送异步请求
CompletableFuture<HttpResponse<String>> future = 
    client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
future.thenApply(HttpResponse::body)
      .thenAccept(System.out::println);

// HTTP/2 支持
HttpClient http2Client = HttpClient.newBuilder()
    .version(HttpClient.Version.HTTP_2)
    .build();

# 3. 新的字符串处理方法

Java 11 为 String 类添加了一些实用的新方法,使字符串处理更加便捷。

示例:

// 判断字符串是否为空白
String str1 = "   ";
boolean isBlank = str1.isBlank(); // 返回 true

// 将字符串转换为流
String str2 = "Hello\nWorld";
Stream<String> lines = str2.lines();
lines.forEach(System.out::println); // 打印 Hello 和 World

// 重复字符串
String str3 = "Java ";
String repeated = str3.repeat(3); // 结果为 "Java Java Java "

// 去除字符串首尾空白
String str4 = "  Java 11  ";
String stripped = str4.strip(); // 结果为 "Java 11"

// 去除字符串尾部空白
String str5 = "  Java 11\t\n";
String strippedEnd = str5.stripTrailing(); // 结果为 "  Java 11"

// 去除字符串首部空白
String str6 = "\t\n  Java 11";
String strippedStart = str6.stripLeading(); // 结果为 "Java 11"

# 4. 集合 API 增强

Java 11 为集合框架添加了一些便利的方法,特别是将集合转换为不可变集合的方法。

示例:

// 创建不可变集合
List<String> list = List.of("Java", "11", "Features");
Set<String> set = Set.of("Java", "11", "Features");
Map<String, Integer> map = Map.of("Java", 8, "Java", 11); // 键冲突会抛出异常
Map<String, Integer> map2 = Map.ofEntries(
    Map.entry("Java 8", 2014),
    Map.entry("Java 11", 2018),
    Map.entry("Java 17", 2021)
);

// 集合转数组
List<String> languages = Arrays.asList("Java", "Python", "JavaScript");
String[] languageArray = languages.toArray(String[]::new);

// 创建不可变集合的副本
List<String> mutableList = new ArrayList<>();
mutableList.add("Java");
mutableList.add("11");
List<String> immutableList = List.copyOf(mutableList);

# 5. ZGC 垃圾收集器

Java 11 引入了实验性的 ZGC(Z Garbage Collector),这是一个低延迟的垃圾收集器,旨在将 GC 暂停时间控制在毫秒级别,同时支持大容量内存(TB 级别)。

使用示例:

# 启用 ZGC 垃圾收集器
java -XX:+UseZGC -jar application.jar

# 设置最大堆内存
java -XX:+UseZGC -Xmx16g -jar application.jar

ZGC 的主要特点:

  • 低延迟(暂停时间小于 10ms)
  • 可伸缩性(支持 TB 级别的堆内存)
  • 并发执行(主要 GC 操作与应用程序线程并发执行)
  • 支持大堆和大对象

# 6. Epsilon 无操作垃圾收集器

Java 11 引入了 Epsilon 垃圾收集器,这是一个特殊的 GC,它不进行任何实际的垃圾回收操作。它主要用于性能测试、内存压力测试和寿命非常短的作业。

使用示例:

# 启用 Epsilon 垃圾收集器
java -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -jar application.jar

Epsilon GC 的主要用途:

  • 性能基准测试(减少 GC 对测试结果的影响)
  • 内存压力测试
  • 寿命极短的作业
  • 确定应用程序的内存分配率
  • 调试 GC 相关问题

# 7. 飞行记录器(JFR)

Java 飞行记录器(JFR)是一个低开销的事件收集框架,用于对 Java 应用程序进行故障诊断和性能分析。在 Java 11 中,JFR 从商业特性变为开源特性。

使用示例:

# 启动应用程序并启用 JFR
java -XX:StartFlightRecording=duration=60s,filename=recording.jfr -jar application.jar

# 从正在运行的应用程序中获取 JFR 记录
jcmd <pid> JFR.start duration=60s filename=recording.jfr
jcmd <pid> JFR.dump filename=dump.jfr
jcmd <pid> JFR.stop

JFR 的主要特点:

  • 低开销(通常小于 1% 的性能影响)
  • 详细的事件收集(包括 JVM 内部事件、Java 应用程序事件等)
  • 可配置性(可以根据需要调整记录的事件类型和细节)
  • 与 Java Mission Control(JMC)工具集成

# 8. 启动单文件源代码程序

Java 11 允许直接运行 Java 源代码文件,而不需要先编译。这对于快速原型设计和学习非常有用。

使用示例:

# 直接运行 Java 源代码文件
java HelloWorld.java

# 传递参数给源代码程序
java HelloWorld.java arg1 arg2

示例代码(HelloWorld.java):

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, Java 11!");
        if (args.length > 0) {
            System.out.println("Arguments: " + String.join(", ", args));
        }
    }
}

# 9. 移除 Java EE 和 CORBA 模块

Java 11 移除了 Java EE 和 CORBA 相关的模块,这些模块在 Java 9 中已被标记为 deprecated for removal。这是 Java 平台模块化的重要一步。

被移除的模块包括:

  • java.xml.ws (JAX-WS)
  • java.xml.bind (JAXB)
  • java.activation (JAF)
  • java.xml.ws.annotation (Common Annotations)
  • java.corba
  • java.transaction
  • java.se.ee

如果需要使用这些功能,可以从 Maven Central 等仓库中获取相应的第三方实现。

# 10. 支持 TLS 1.3

Java 11 增加了对 TLS 1.3 协议的支持,提供了更好的安全性和性能。TLS 1.3 是 TLS 协议的重大更新,简化了握手过程,提供了更强的加密算法。

使用示例:

// 创建支持 TLS 1.3 的 SSL 上下文
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
sslContext.init(null, null, null);

// 创建 SSL 套接字工厂
SSLSocketFactory socketFactory = sslContext.getSocketFactory();

// 检查是否支持 TLS 1.3
String[] supportedProtocols = socketFactory.getSupportedProtocols();
boolean tls13Supported = Arrays.asList(supportedProtocols).contains("TLSv1.3");

TLS 1.3 的主要优势:

  • 更安全(移除了旧的、不安全的加密算法)
  • 更快的握手(减少了往返次数)
  • 更好的隐私保护
  • 简化的协议设计

# 三、代码案例

# 1. 使用 HTTP Client API 访问 RESTful API

案例: 使用 Java 11 的 HTTP Client API 访问一个 RESTful API 并处理响应。

示例:

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;

public class HttpClientExample {
    public static void main(String[] args) throws Exception {
        // 创建 HTTP 客户端
        HttpClient client = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_2)
            .connectTimeout(Duration.ofSeconds(10))
            .build();

        // 创建 HTTP 请求
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://jsonplaceholder.typicode.com/posts/1"))
            .header("Accept", "application/json")
            .GET()
            .build();

        // 发送同步请求
        HttpResponse<String> response = client.send(request,
            HttpResponse.BodyHandlers.ofString());
        System.out.println("Status Code: " + response.statusCode());
        System.out.println("Response Body: " + response.body());

        // 发送异步请求
        CompletableFuture<HttpResponse<String>> future = 
            client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
        future.thenApply(HttpResponse::body)
              .thenAccept(body -> System.out.println("Async Response: " + body))
              .join();

        // 发送 POST 请求
        HttpRequest postRequest = HttpRequest.newBuilder()
            .uri(URI.create("https://jsonplaceholder.typicode.com/posts"))
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString("{\"title\":\"foo\",\"body\":\"bar\",\"userId\":1}"))
            .build();
        HttpResponse<String> postResponse = client.send(postRequest,
            HttpResponse.BodyHandlers.ofString());
        System.out.println("POST Status: " + postResponse.statusCode());
    }
}

# 2. 使用 String 新方法处理文本

案例: 使用 Java 11 中 String 类的新方法处理文本数据。

示例:

import java.util.stream.Collectors;

public class StringMethodsExample {
    public static void main(String[] args) {
        // 示例文本
        String text = "\n  Java 11 新特性\n  String 方法增强\t\n  ";

        // 检查是否为空白
        System.out.println("Is blank: " + text.isBlank()); // false
        System.out.println("Is blank: " + "\t\n\r".isBlank()); // true

        // 去除空白
        String stripped = text.strip();
        System.out.println("Stripped: [" + stripped + "]");

        String strippedStart = text.stripLeading();
        System.out.println("Stripped start: [" + strippedStart + "]");

        String strippedEnd = text.stripTrailing();
        System.out.println("Stripped end: [" + strippedEnd + "]");

        // 转换为行流并处理
        String multilineText = "Line 1\nLine 2\nLine 3";
        String result = multilineText.lines()
            .filter(line -> line.contains("2"))
            .collect(Collectors.joining(", "));
        System.out.println("Filtered lines: " + result);

        // 重复字符串
        String repeated = "Java ".repeat(3);
        System.out.println("Repeated: " + repeated);

        // 计算字符串的空白部分
        long whitespaceCount = text.chars()
            .filter(Character::isWhitespace)
            .count();
        System.out.println("Whitespace count: " + whitespaceCount);
    }
}

# 四、Java 11 新特性的优势与最佳实践

# 1. 优势总结

Java 11 新特性带来的主要优势:

  • 现代 HTTP 客户端:标准化的 HTTP Client API 使网络编程更加简单高效
  • 性能优化:ZGC 等新的垃圾收集器提供了更好的性能和更低的延迟
  • 代码简化:局部变量类型推断增强、新的字符串方法等使代码更加简洁
  • 安全性提升:支持 TLS 1.3 提供了更好的安全保障
  • 开发效率:启动单文件源代码程序等特性提高了开发效率
  • 长期支持:作为 LTS 版本,提供了长期的支持和稳定性

# 2. 最佳实践

使用 Java 11 新特性的最佳实践:

  • 优先使用 HTTP Client API:替代传统的 HttpURLConnection,享受更好的性能和 API 设计
  • 合理选择垃圾收集器:根据应用程序的特点选择合适的 GC,如对延迟敏感的应用考虑 ZGC
  • 充分利用字符串新方法:使用 isBlank()、lines()、repeat()、strip() 等方法简化字符串处理
  • 使用不可变集合:使用 List.of()、Set.of()、Map.of() 等方法创建不可变集合
  • 注意模块路径变化:了解并适应 Java EE 和 CORBA 模块的移除
  • 利用 JFR 进行性能分析:使用 JFR 收集低开销的性能数据进行分析
  • 保持代码兼容性:在升级过程中注意潜在的兼容性问题

# 3. 常见陷阱和注意事项

使用 Java 11 新特性时需要注意的常见陷阱:

  • 过度使用局部变量类型推断:在复杂的场景中过度使用 var 可能会降低代码可读性
  • ZGC 的实验性质:Java 11 中的 ZGC 仍然是实验性的,在生产环境中使用需要谨慎
  • 忽略 TLS 配置:启用 TLS 1.3 时需要确保所有客户端都支持该协议
  • 忘记添加移除的模块依赖:如果应用程序依赖于被移除的 Java EE 模块,需要添加相应的第三方库
  • 错误使用不可变集合:尝试修改不可变集合会抛出 UnsupportedOperationException
  • JFR 性能影响:虽然 JFR 的开销很小,但在极端性能敏感的场景中仍需注意
  • 忽略兼容性检查:从旧版本升级到 Java 11 时,应当进行全面的兼容性测试