Java 11作为第一个LTS版本,带来了革命性的字符串API增强、HTTP客户端标准化和ZGC垃圾回收器等重要特性。本文将深入剖析Java 11的核心新特性,从字符串处理到现代化基础设施,带你体验LTS版本的稳定与创新。

🎯 Java 11变革背景

LTS版本的重要意义

Java 11是Oracle发布周期改革后的第一个长期支持(LTS)版本:

  • LTS承诺:8年的免费支持和更新
  • 企业友好:稳定的生产环境选择
  • 功能平衡:既保持创新又保证稳定性
  • 生态影响:影响了整个Java生态的发展方向

现代化与性能的双重追求

现代化方面

  • 字符串API的全面增强
  • HTTP客户端的标准化
  • 文件操作的简化
  • Unicode 10支持

性能方面

  • ZGC垃圾回收器:可扩展的低延迟GC
  • Epsilon GC:用于性能测试和内存压力测试
  • 运行时镜像:AOT编译支持
  • 动态类文件常量:提升常量加载性能

🔤 字符串API增强:现代字符串处理

1. 传统字符串处理的局限性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// Java 10及之前:字符串处理繁琐且易错
public class StringUtilsJava10 {

// 1. 检查空字符串或只包含空白字符
public static boolean isBlank(String str) {
if (str == null) return true;
for (int i = 0; i < str.length(); i++) {
if (!Character.isWhitespace(str.charAt(i))) {
return false;
}
}
return true;
}

// 2. 按行分割字符串
public static List<String> lines(String str) {
List<String> result = new ArrayList<>();
if (str == null || str.isEmpty()) return result;

int start = 0;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c == '\n' || c == '\r') {
if (start < i) {
result.add(str.substring(start, i));
}
if (c == '\r' && i + 1 < str.length() && str.charAt(i + 1) == '\n') {
i++; // 跳过\r\n中的\n
}
start = i + 1;
}
}
if (start < str.length()) {
result.add(str.substring(start));
}
return result;
}

// 3. 去除首尾空白字符
public static String strip(String str) {
if (str == null) return null;
return str.trim(); // 只去除ASCII空白字符
}

// 4. 重复字符串
public static String repeat(String str, int count) {
if (str == null) return null;
if (count <= 0) return "";
if (count == 1) return str;

StringBuilder sb = new StringBuilder(str.length() * count);
for (int i = 0; i < count; i++) {
sb.append(str);
}
return sb.toString();
}
}

2. Java 11字符串API的优雅解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// Java 11:内置的字符串处理方法
public class StringUtilsJava11 {

// 1. isBlank() - 检查空字符串或只包含空白字符
public static void demonstrateIsBlank() {
String empty = "";
String spaces = " ";
String tabs = "\t\t";
String content = " hello ";

System.out.println("\"\".isBlank(): " + "".isBlank()); // true
System.out.println("\" \".isBlank(): " + " ".isBlank()); // true
System.out.println("\"\\t\\t\".isBlank(): " + "\t\t".isBlank()); // true
System.out.println("\" hello \".isBlank(): " + " hello ".isBlank()); // false

// 对比传统方法
System.out.println("传统isBlank(\" \"): " + isBlankTraditional(" "));
}

// 2. lines() - 按行分割字符串
public static void demonstrateLines() {
String multiline = "Hello\nWorld\r\nJava\r11";

// Java 11方式
multiline.lines().forEach(line -> {
System.out.println("Line: '" + line + "'");
});
// 输出:
// Line: 'Hello'
// Line: 'World'
// Line: 'Java'
// Line: '11'

// 对比传统方式
System.out.println("传统lines(): " + linesTraditional(multiline));
}

// 3. strip() - 去除首尾空白字符(支持Unicode空白字符)
public static void demonstrateStrip() {
String text = " \u2000\u2001hello\u2002\u2003 "; // Unicode空白字符

System.out.println("原始字符串长度: " + text.length());
System.out.println("strip()结果: '" + text.strip() + "'");
System.out.println("strip()后长度: " + text.strip().length());

// stripLeading() - 只去除前导空白
System.out.println("stripLeading(): '" + text.stripLeading() + "'");

// stripTrailing() - 只去除尾部空白
System.out.println("stripTrailing(): '" + text.stripTrailing() + "'");

// 对比trim()
System.out.println("trim()结果: '" + text.trim() + "'"); // 只去除ASCII空白
System.out.println("trim()后长度: " + text.trim().length());
}

// 4. repeat() - 重复字符串
public static void demonstrateRepeat() {
String pattern = "*-";

System.out.println("\"*-\".repeat(5): " + pattern.repeat(5)); // *-*-*-*-*-
System.out.println("\"Hello\".repeat(3): " + "Hello".repeat(3)); // HelloHelloHello
System.out.println("\"A\".repeat(0): " + "A".repeat(0)); // 空字符串
System.out.println("\"Test\".repeat(1): " + "Test".repeat(1)); // Test

// 实际应用:生成分隔符
String separator = "=".repeat(50);
System.out.println(separator);
System.out.println("Java 11 String API Demo");
System.out.println(separator);
}

// 传统方法的实现(仅用于对比)
private static boolean isBlankTraditional(String str) {
return str == null || str.trim().isEmpty();
}

private static List<String> linesTraditional(String str) {
return Arrays.asList(str.split("\\r?\\n"));
}
}

字符串API增强的优势

  • Unicode友好:正确处理所有Unicode空白字符
  • 性能优化:内置实现比自定义方法更高效
  • 空安全:正确处理null值
  • 一致性:API设计保持一致

🌐 HTTP客户端标准化:现代网络通信

1. Java 10 HTTP客户端的局限性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Java 10:HTTP客户端已经很强大,但还有改进空间
import java.net.http.*;
import java.net.URI;
import java.time.Duration;

public class HttpClientJava10 {

private static final HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(10))
.build();

// 同步GET请求
public static String getSync(String url) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("User-Agent", "Java-10-Client")
.timeout(Duration.ofSeconds(5))
.build();

HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());

return response.statusCode() == 200 ? response.body() : null;
}

// 异步GET请求
public static CompletableFuture<String> getAsync(String url) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.build();

return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(response -> response.body());
}
}

2. Java 11 HTTP客户端的增强

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Java 11:HTTP客户端标准化,成为正式API
import java.net.http.*;
import java.net.URI;
import java.time.Duration;
import java.net.Authenticator;
import java.net.PasswordAuthentication;

public class HttpClientJava11 {

// 1. 创建HTTP客户端 - 更丰富的配置选项
private static final HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2) // HTTP/2优先
.connectTimeout(Duration.ofSeconds(10))
.followRedirects(HttpClient.Redirect.NORMAL) // 自动重定向
.authenticator(new Authenticator() { // 认证支持
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("user", "password".toCharArray());
}
})
.build();

// 2. 同步GET请求 - 更完善的错误处理
public static HttpResponse<String> getSync(String url) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("User-Agent", "Java-11-Client")
.header("Accept", "application/json")
.timeout(Duration.ofSeconds(5))
.build();

HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());

// Java 11增强:更好的状态码处理
switch (response.statusCode()) {
case 200:
return response;
case 404:
throw new RuntimeException("Resource not found: " + url);
case 500:
throw new RuntimeException("Server error: " + url);
default:
throw new RuntimeException("HTTP error: " + response.statusCode());
}
}

// 3. POST请求 - 更灵活的请求体处理
public static HttpResponse<String> postJson(String url, String jsonData) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + getAuthToken())
.POST(HttpRequest.BodyPublishers.ofString(jsonData))
.build();

return httpClient.send(request, HttpResponse.BodyHandlers.ofString());
}

// 4. 异步请求链 - 更流畅的异步编程
public static CompletableFuture<String> getAsyncChain(String url) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.build();

return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body) // 提取响应体
.thenApply(String::toUpperCase) // 转换大写
.thenApply(body -> "Processed: " + body) // 添加前缀
.exceptionally(throwable -> { // 异常处理
System.err.println("Async request failed: " + throwable.getMessage());
return "Error occurred";
});
}

// 5. WebSocket支持增强
public static void webSocketExample() {
WebSocket webSocket = httpClient.newWebSocketBuilder()
.buildAsync(URI.create("wss://echo.websocket.org"), new WebSocket.Listener() {
@Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
System.out.println("Received: " + data);
if (last) {
webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "Client closing");
}
return null;
}

@Override
public void onError(WebSocket webSocket, Throwable error) {
System.err.println("WebSocket error: " + error.getMessage());
}
}).join();

// 发送消息
webSocket.sendText("Hello from Java 11!", true);

// 等待一段时间
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}

// 6. 文件上传下载
public static void fileUploadDownload() throws Exception {
// 上传文件
Path filePath = Paths.get("data.txt");
HttpRequest uploadRequest = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/upload"))
.POST(HttpRequest.BodyPublishers.ofFile(filePath))
.build();

HttpResponse<String> uploadResponse = httpClient.send(uploadRequest,
HttpResponse.BodyHandlers.ofString());

// 下载文件到本地
HttpRequest downloadRequest = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/download/file.txt"))
.build();

HttpResponse<Path> downloadResponse = httpClient.send(downloadRequest,
HttpResponse.BodyHandlers.ofFile(Paths.get("downloaded.txt")));

System.out.println("File downloaded to: " + downloadResponse.body());
}

// 辅助方法
private static String getAuthToken() {
return "your-jwt-token-here";
}
}

HTTP客户端增强

  • 标准化API:成为Java标准库的一部分
  • 更好的认证支持:内置认证机制
  • 增强的异步支持:更流畅的异步链式调用
  • 文件操作支持:直接上传下载文件
  • WebSocket改进:更好的WebSocket支持

📁 文件方法增强:简化的文件操作

1. Java 10文件操作的复杂性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Java 10及之前:文件读写繁琐
import java.io.*;
import java.nio.file.*;
import java.util.stream.Stream;

public class FileUtilsJava10 {

// 读取整个文件为字符串
public static String readAllText(String filePath) throws IOException {
byte[] bytes = Files.readAllBytes(Paths.get(filePath));
return new String(bytes, StandardCharsets.UTF_8);
}

// 写入字符串到文件
public static void writeAllText(String filePath, String content) throws IOException {
Files.write(Paths.get(filePath), content.getBytes(StandardCharsets.UTF_8));
}

// 读取文件所有行
public static List<String> readAllLines(String filePath) throws IOException {
return Files.readAllLines(Paths.get(filePath), StandardCharsets.UTF_8);
}

// 写入多行到文件
public static void writeAllLines(String filePath, List<String> lines) throws IOException {
Files.write(Paths.get(filePath), lines, StandardCharsets.UTF_8);
}
}

2. Java 11文件方法的简化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Java 11:简化的文件读写方法
import java.io.IOException;
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Stream;

public class FileUtilsJava11 {

// 1. readString() - 读取整个文件为字符串
public static String readStringSimple(String filePath) throws IOException {
Path path = Paths.get(filePath);
return Files.readString(path); // 默认UTF-8编码
}

// 指定编码读取
public static String readStringWithCharset(String filePath) throws IOException {
Path path = Paths.get(filePath);
return Files.readString(path, StandardCharsets.UTF_16);
}

// 2. writeString() - 写入字符串到文件
public static void writeStringSimple(String filePath, String content) throws IOException {
Path path = Paths.get(filePath);
Files.writeString(path, content); // 默认UTF-8编码
}

// 指定编码和写入选项
public static void writeStringAdvanced(String filePath, String content) throws IOException {
Path path = Paths.get(filePath);
Files.writeString(path, content, StandardCharsets.UTF_8,
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
}

// 3. 追加写入
public static void appendString(String filePath, String content) throws IOException {
Path path = Paths.get(filePath);
Files.writeString(path, content, StandardOpenOption.CREATE, StandardOpenOption.APPEND);
}

// 4. 读取文件为字节数组(保持原有功能)
public static byte[] readAllBytes(String filePath) throws IOException {
return Files.readAllBytes(Paths.get(filePath));
}

// 5. 写入字节数组(保持原有功能)
public static void writeBytes(String filePath, byte[] data) throws IOException {
Files.write(Paths.get(filePath), data);
}

// 6. 实际应用示例
public static void demonstrateFileOperations() throws IOException {
String configPath = "config.properties";
String logPath = "app.log";

// 读取配置文件
if (Files.exists(Paths.get(configPath))) {
String config = Files.readString(Paths.get(configPath));
System.out.println("Config content: " + config);
} else {
// 创建默认配置
String defaultConfig = """
app.name=MyApp
app.version=1.0
app.debug=true
""";
Files.writeString(Paths.get(configPath), defaultConfig);
System.out.println("Default config created");
}

// 写入日志
String logEntry = String.format("[%s] Application started%n",
java.time.LocalDateTime.now());
appendString(logPath, logEntry);

// 读取日志最后几行
if (Files.exists(Paths.get(logPath))) {
List<String> lines = Files.readAllLines(Paths.get(logPath));
int startIndex = Math.max(0, lines.size() - 5);
lines.subList(startIndex, lines.size()).forEach(System.out::println);
}
}

// 7. 与Stream结合使用
public static void streamFileProcessing(String inputPath, String outputPath) throws IOException {
Path input = Paths.get(inputPath);
Path output = Paths.get(outputPath);

// 读取、处理、写入一条龙
Stream<String> lines = Files.lines(input);
String processedContent = lines
.map(String::toUpperCase) // 转换为大写
.map(line -> line.replaceAll("\\s+", " ")) // 压缩空白字符
.filter(line -> !line.trim().isEmpty()) // 过滤空行
.collect(java.util.stream.Collectors.joining("\n"));

Files.writeString(output, processedContent);
}

// 8. 临时文件操作
public static void temporaryFileOperations() throws IOException {
// 创建临时文件
Path tempFile = Files.createTempFile("temp", ".txt");
Files.writeString(tempFile, "Temporary content");

// 读取临时文件
String content = Files.readString(tempFile);
System.out.println("Temp file content: " + content);

// 删除临时文件
Files.delete(tempFile);
System.out.println("Temp file deleted: " + Files.notExists(tempFile));
}
}

文件方法增强的优势

  • 简化APIreadString()writeString()简化操作
  • 编码友好:默认UTF-8,支持自定义编码
  • 选项丰富:支持追加、创建、覆盖等多种操作
  • 性能优化:针对字符串操作优化

🗂️ 集合API增强:更实用的集合操作

1. Java 10集合操作的局限性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Java 10及之前:集合转换为数组繁琐
public class CollectionUtilsJava10 {

// toArray()方法需要类型参数
public static void demonstrateToArray() {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// 转换为Object数组 - 繁琐
Object[] objectArray = names.toArray();
System.out.println("Object array: " + Arrays.toString(objectArray));

// 转换为String数组 - 需要类型参数
String[] stringArray = names.toArray(new String[0]);
System.out.println("String array: " + Arrays.toString(stringArray));

// 自定义数组大小
String[] sizedArray = names.toArray(new String[names.size()]);
System.out.println("Sized array: " + Arrays.toString(sizedArray));
}
}

2. Java 11集合API的改进

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Java 11:简化的toArray()方法
import java.util.*;
import java.util.stream.Collectors;

public class CollectionUtilsJava11 {

// 1. toArray()方法改进
public static void demonstrateToArray() {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Diana");

// Java 11方式:直接转换为正确类型的数组
String[] stringArray = names.toArray(String[]::new);
System.out.println("String array: " + Arrays.toString(stringArray));

// 对比Java 10方式
String[] oldWay = names.toArray(new String[0]);
System.out.println("Old way: " + Arrays.toString(oldWay));

// Set转换为数组
Set<Integer> numbers = Set.of(1, 2, 3, 4, 5);
Integer[] numberArray = numbers.toArray(Integer[]::new);
System.out.println("Number array: " + Arrays.toString(numberArray));
}

// 2. 结合Stream使用
public static void streamAndCollection() {
List<String> names = Arrays.asList("alice", "bob", "charlie", "diana");

// 过滤并转换为数组
String[] filteredNames = names.stream()
.filter(name -> name.length() > 3)
.map(String::toUpperCase)
.toArray(String[]::new);

System.out.println("Filtered names: " + Arrays.toString(filteredNames));

// 分组后转换为数组
Map<Integer, List<String>> groupedByLength = names.stream()
.collect(Collectors.groupingBy(String::length));

for (Map.Entry<Integer, List<String>> entry : groupedByLength.entrySet()) {
String[] groupArray = entry.getValue().toArray(String[]::new);
System.out.println("Length " + entry.getKey() + ": " + Arrays.toString(groupArray));
}
}

// 3. 实际应用场景
public static void realWorldExamples() {
// 数据库查询结果转换为数组
List<User> users = getUsersFromDatabase();
User[] userArray = users.toArray(User[]::new);

// API响应数据转换
List<Order> orders = getOrdersFromAPI();
String[] orderIds = orders.stream()
.map(Order::getId)
.toArray(String[]::new);

// 文件列表转换为数组
List<Path> files = getFilesFromDirectory();
String[] fileNames = files.stream()
.map(Path::getFileName)
.map(Path::toString)
.toArray(String[]::new);

System.out.println("Users: " + Arrays.toString(userArray));
System.out.println("Order IDs: " + Arrays.toString(orderIds));
System.out.println("File names: " + Arrays.toString(fileNames));
}

// 模拟数据类
static class User {
private final String name;
User(String name) { this.name = name; }
@Override
public String toString() { return name; }
}

static class Order {
private final String id;
Order(String id) { this.id = id; }
public String getId() { return id; }
@Override
public String toString() { return "Order:" + id; }
}

// 模拟数据获取方法
private static List<User> getUsersFromDatabase() {
return Arrays.asList(new User("Alice"), new User("Bob"));
}

private static List<Order> getOrdersFromAPI() {
return Arrays.asList(new Order("001"), new Order("002"));
}

private static List<Path> getFilesFromDirectory() {
return Arrays.asList(
java.nio.file.Paths.get("file1.txt"),
java.nio.file.Paths.get("file2.txt")
);
}
}

集合API增强的优势

  • 类型安全toArray(String[]::new)确保类型正确
  • 简洁明了:减少样板代码
  • 性能优化:避免不必要的数组复制
  • 灵活性:支持所有集合类型

🎭 Optional增强:更优雅的空值处理

1. Java 10 Optional的不足

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Java 10:Optional还缺少一些实用方法
public class OptionalExampleJava10 {

public static void demonstrateOptional() {
Optional<String> optional = Optional.ofNullable(getValue());

// 检查是否为空 - 需要使用!isPresent()
if (!optional.isPresent()) {
System.out.println("Value is empty");
}

// 或者使用isPresent()判断
if (optional.isPresent()) {
System.out.println("Value: " + optional.get());
} else {
System.out.println("Value is empty");
}

// 复杂的条件判断
if (optional.isPresent() && optional.get().length() > 5) {
System.out.println("Long value: " + optional.get());
}
}

private static String getValue() {
return Math.random() > 0.5 ? "Hello World" : null;
}
}

2. Java 11 Optional的改进

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Java 11:新增isEmpty()方法
public class OptionalExampleJava11 {

// 1. isEmpty()方法 - 更直观的空值检查
public static void demonstrateIsEmpty() {
Optional<String> optional = Optional.ofNullable(getValue());

// Java 11方式:更直观
if (optional.isEmpty()) {
System.out.println("Value is empty");
} else {
System.out.println("Value: " + optional.get());
}

// 对比Java 10方式
if (!optional.isPresent()) { // 较不直观
System.out.println("Value is empty (old way)");
}
}

// 2. 结合其他Optional方法使用
public static void advancedOptionalUsage() {
List<Optional<String>> optionals = Arrays.asList(
Optional.of("Hello"),
Optional.empty(),
Optional.of("World"),
Optional.empty()
);

// 过滤非空值
List<String> nonEmptyValues = optionals.stream()
.filter(Optional::isPresent) // Java 10及之前
.map(Optional::get)
.collect(Collectors.toList());

// 使用isEmpty()过滤空值
List<String> nonEmptyValuesNew = optionals.stream()
.filter(optional -> !optional.isEmpty()) // Java 11方式
.map(Optional::get)
.collect(Collectors.toList());

System.out.println("Non-empty values: " + nonEmptyValues);
System.out.println("Non-empty values (new): " + nonEmptyValuesNew);

// 统计空值和非空值
long emptyCount = optionals.stream().filter(Optional::isEmpty).count();
long presentCount = optionals.stream().filter(Optional::isPresent).count();

System.out.println("Empty optionals: " + emptyCount);
System.out.println("Present optionals: " + presentCount);
}

// 3. 实际应用场景
public static void realWorldOptional() {
// 用户服务
User user = findUserById("123");

Optional<String> userName = Optional.ofNullable(user)
.map(User::getName);

// Java 11方式:更清晰的条件判断
if (userName.isEmpty()) {
System.out.println("User not found or has no name");
} else {
System.out.println("User name: " + userName.get());
}

// 或者使用ifPresentOrElse (Java 9)
userName.ifPresentOrElse(
name -> System.out.println("Found user: " + name),
() -> System.out.println("User not found")
);

// 配置文件读取
Optional<String> configValue = readConfig("app.timeout");

// 空值处理
int timeout = configValue
.filter(value -> !value.trim().isEmpty())
.map(Integer::parseInt)
.orElse(30); // 默认30秒

System.out.println("Timeout: " + timeout + " seconds");
}

// 4. 链式调用优化
public static void chainOptimization() {
Optional<String> result = getData()
.filter(data -> data.length() > 10)
.map(String::toUpperCase);

// Java 11方式:更清晰的处理逻辑
if (result.isEmpty()) {
System.out.println("No valid data found");
} else {
String processedData = result.get();
System.out.println("Processed data: " + processedData);
}

// 或者使用流畅的链式调用
String finalResult = result.orElse("DEFAULT_VALUE");
System.out.println("Final result: " + finalResult);
}

// 辅助方法
private static String getValue() {
return Math.random() > 0.5 ? "Hello Java 11" : null;
}

private static User findUserById(String id) {
// 模拟数据库查询
return "123".equals(id) ? new User("Alice") : null;
}

private static String readConfig(String key) {
// 模拟配置文件读取
return "app.timeout".equals(key) ? "60" : null;
}

// 数据类
static class User {
private final String name;
User(String name) { this.name = name; }
public String getName() { return name; }
}

private static Optional<String> getData() {
return Optional.ofNullable(Math.random() > 0.3 ? "Short" : "This is a long data string");
}
}

Optional增强的优势

  • 更直观isEmpty()!isPresent()更清晰
  • 代码一致性:与其他集合类的API保持一致
  • 可读性提升:减少否定逻辑,代码更易理解
  • 现代化:符合现代编程语言的设计理念

⚡ Lambda参数的var语法

1. Java 10 Lambda参数的限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Java 10:Lambda参数不能使用var
import java.util.function.Function;

public class LambdaVarJava10 {

public static void main(String[] args) {
// 正常Lambda表达式
Function<String, Integer> lengthFunc = s -> s.length();

// 显式类型声明
Function<String, Integer> lengthFunc2 = (String s) -> s.length();

// Java 10中不能使用var
// Function<String, Integer> lengthFunc3 = (var s) -> s.length(); // 编译错误
}
}

2. Java 11 Lambda参数的var语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// Java 11:Lambda参数可以使用var
import java.util.function.*;
import java.util.List;
import java.util.stream.Collectors;

public class LambdaVarJava11 {

// 1. 基本var语法
public static void demonstrateBasicVar() {
// 使用var声明Lambda参数
Function<String, Integer> lengthFunc = (var s) -> s.length();
BiFunction<String, String, String> concatFunc = (var s1, var s2) -> s1 + s2;

System.out.println("Length: " + lengthFunc.apply("Hello"));
System.out.println("Concat: " + concatFunc.apply("Hello", " World"));
}

// 2. 结合类型注解使用
public static void demonstrateVarWithAnnotations() {
// var可以结合注解使用
Function<String, Integer> annotatedFunc = (@SuppressWarnings("unused") var s) -> s.length();

// 多个参数的注解
BiFunction<String, String, Boolean> compareFunc = (
(@NonNull var s1),
(@NonNull var s2)
) -> s1.length() > s2.length();

System.out.println("Compare result: " + compareFunc.apply("Hello", "Hi"));
}

// 3. 在Stream中使用
public static void demonstrateStreamUsage() {
List<String> names = List.of("Alice", "Bob", "Charlie", "Diana");

// 使用var简化Lambda参数
List<String> upperNames = names.stream()
.map((var name) -> name.toUpperCase())
.collect(Collectors.toList());

// 复杂的数据处理
Map<Integer, List<String>> groupedByLength = names.stream()
.collect(Collectors.groupingBy((var name) -> name.length()));

System.out.println("Upper names: " + upperNames);
System.out.println("Grouped by length: " + groupedByLength);
}

// 4. 实际应用场景
public static void realWorldUsage() {
// 数据验证和转换
List<User> users = getUsers();

List<String> validNames = users.stream()
.filter((var user) -> user.getName() != null && !user.getName().isBlank())
.map((var user) -> user.getName().strip().toUpperCase())
.filter((var name) -> name.length() >= 3)
.collect(Collectors.toList());

// 异步数据处理
CompletableFuture<List<String>> future = CompletableFuture.supplyAsync(() -> {
return users.stream()
.map((var user) -> "User: " + user.getName())
.collect(Collectors.toList());
});

System.out.println("Valid names: " + validNames);
future.thenAccept(result -> System.out.println("Async result: " + result));
}

// 5. 自定义注解示例
@interface NonNull {}

@SuppressWarnings("unused")
public static void annotationExample() {
Predicate<String> validator = (@NonNull var input) -> input != null && !input.isEmpty();
System.out.println("Validation result: " + validator.test("test"));
}

// 辅助类和方法
static class User {
private final String name;
User(String name) { this.name = name; }
public String getName() { return name; }
}

private static List<User> getUsers() {
return List.of(
new User("Alice"),
new User("Bob"),
new User(null),
new User(" Charlie "),
new User("Diana")
);
}
}

Lambda var语法的优势

  • 一致性:与方法参数的var语法保持一致
  • 注解支持:可以在Lambda参数上使用注解
  • 可读性:在复杂类型推断时更清晰
  • 现代化:符合现代Java的语法风格

🗑️ 垃圾回收器革新:ZGC和Epsilon

1. ZGC:可扩展的低延迟垃圾回收器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Java 11:ZGC - 专为大堆内存设计
// 启动参数
java -XX:+UseZGC \
-Xmx16g \
-Xms16g \
-XX:ZCollectionInterval=5 \
-XX:ZAllocationSpikeTolerance=2.0 \
com.example.App

// ZGC特性:
// - 最大暂停时间不超过10ms
// - 支持TB级堆内存
// - 与G1相比,更好的大堆性能
// - 并发处理所有阶段

2. Epsilon GC:用于性能测试

1
2
3
4
5
6
7
8
9
10
11
12
// Java 11:Epsilon GC - 什么都不做的垃圾回收器
// 用于性能测试和内存压力测试
java -XX:+UseEpsilonGC \
-Xmx1g \
-XX:+PrintGCDetails \
com.example.App

// Epsilon GC特性:
// - 不进行任何垃圾回收
// - 当堆内存耗尽时直接退出
// - 用于测试应用的最大内存使用
// - 测量GC开销

📊 性能测试和对比

1. 字符串API性能对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class StringPerformanceTest {

private static final String TEST_DATA = " \u2000Hello\u2001World\u2002 \nLine1\r\nLine2\rLine3 ";
private static final int ITERATIONS = 100000;

public static void main(String[] args) {
// 测试isBlank性能
long startTime = System.nanoTime();
for (int i = 0; i < ITERATIONS; i++) {
boolean result = TEST_DATA.isBlank();
}
long endTime = System.nanoTime();
System.out.println("isBlank() time: " + (endTime - startTime) / 1_000_000 + "ms");

// 测试strip性能
startTime = System.nanoTime();
for (int i = 0; i < ITERATIONS; i++) {
String result = TEST_DATA.strip();
}
endTime = System.nanoTime();
System.out.println("strip() time: " + (endTime - startTime) / 1_000_000 + "ms");

// 测试lines性能
startTime = System.nanoTime();
for (int i = 0; i < ITERATIONS; i++) {
long count = TEST_DATA.lines().count();
}
endTime = System.nanoTime();
System.out.println("lines() time: " + (endTime - startTime) / 1_000_000 + "ms");
}
}

2. HTTP客户端性能测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class HttpClientPerformanceTest {

private static final HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.build();

public static void testHttpPerformance() throws Exception {
String url = "https://httpbin.org/get";
int requests = 100;

long startTime = System.nanoTime();

// 并行发送请求
List<CompletableFuture<HttpResponse<String>>> futures = new ArrayList<>();
for (int i = 0; i < requests; i++) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.build();

CompletableFuture<HttpResponse<String>> future = httpClient
.sendAsync(request, HttpResponse.BodyHandlers.ofString());
futures.add(future);
}

// 等待所有请求完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

long endTime = System.nanoTime();
long totalTime = (endTime - startTime) / 1_000_000; // 毫秒

System.out.println("Total time for " + requests + " requests: " + totalTime + "ms");
System.out.println("Average time per request: " + (totalTime * 1.0 / requests) + "ms");
System.out.println("Requests per second: " + (requests * 1000.0 / totalTime));
}
}

🎯 Java 11变革总结

核心变革内容对比

特性 Java 10及之前 Java 11 改进程度
字符串API 基础操作 isBlank/lines/strip/repeat 📈 显著增强
HTTP客户端 预览版 正式标准化 ✅ 稳定可用
文件操作 readAllBytes readString/writeString 📝 大幅简化
集合API 基础toArray 泛型toArray方法 🔧 语法简化
Optional 基础方法 isEmpty()方法 🛡️ 更直观
Lambda参数 无var支持 var语法支持 🎯 语法一致
GC选择 G1为主 ZGC/Epsilon可选 ⚡ 更多选择

为什么需要这些变革?

1. LTS版本的稳定性保证

  • 8年支持周期,需要经过充分测试的功能
  • 平衡创新与稳定的最佳选择
  • 企业用户的首选版本

2. 开发者体验的持续提升

  • 字符串处理是最常见的操作,需要更好支持
  • HTTP客户端需要标准化,成为核心API
  • 文件操作需要简化,减少样板代码

3. 现代应用的需求

  • 大堆内存应用需要ZGC
  • 性能测试需要Epsilon GC
  • 异步编程需要更好的HTTP支持

4. 生态系统的完善

  • 移除过时的Java EE模块
  • 统一JDK仓库
  • Unicode 10支持

相对于Java 10的优势

1. 字符串处理的革命

  • isBlank()lines()strip()repeat()等实用方法
  • Unicode空白字符正确支持
  • 性能优化和内存效率提升

2. 网络编程的标准化

  • HTTP客户端成为正式API
  • 更好的异步支持和错误处理
  • WebSocket和文件操作支持

3. API设计的完善

  • Optional.isEmpty()更直观
  • 集合toArray()方法简化
  • Lambda var语法一致性

4. 垃圾回收的选择丰富

  • ZGC满足大堆内存需求
  • Epsilon GC支持性能测试
  • 运行时镜像优化启动速度

🚀 最佳实践指南

1. 字符串API的最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 字符串处理最佳实践
public class StringBestPractices {

// ✅ 推荐:使用Java 11字符串方法
public static void modernStringProcessing() {
String input = " \u2000Hello\u2001World\u2002 \nLine1\r\nLine2 ";

// 检查空白字符串
if (input.isBlank()) {
System.out.println("Input is blank");
return;
}

// 去除空白字符
String cleanInput = input.strip();

// 按行处理
cleanInput.lines()
.filter(line -> !line.isBlank()) // 过滤空行
.map(String::toUpperCase) // 转换大写
.forEach(System.out::println);

// 重复字符串创建分隔符
String separator = "=".repeat(30);
System.out.println(separator);
}

// ❌ 避免:使用过时的字符串处理方式
public static void legacyStringProcessing() {
String input = " Hello World ";

// 不要这样检查空字符串
if (input == null || input.trim().isEmpty()) { // 错过Unicode空白字符
return;
}

// 不要这样按行分割
String[] lines = input.split("\\r?\\n"); // 正则表达式开销大
}
}

2. HTTP客户端的最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// HTTP客户端最佳实践
public class HttpClientBestPractices {

private static final HttpClient httpClient = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(10))
.followRedirects(HttpClient.Redirect.NORMAL)
.build();

// ✅ 推荐:结构化的HTTP请求处理
public static HttpResponse<String> getWithRetry(String url, int maxRetries) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("User-Agent", "Java-11-App")
.timeout(Duration.ofSeconds(5))
.build();

for (int i = 0; i < maxRetries; i++) {
try {
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());

if (response.statusCode() == 200) {
return response;
}

// 指数退避重试
if (i < maxRetries - 1) {
Thread.sleep(1000 * (int) Math.pow(2, i));
}

} catch (Exception e) {
if (i == maxRetries - 1) {
throw new RuntimeException("HTTP request failed after " + maxRetries + " retries", e);
}
}
}

throw new RuntimeException("HTTP request failed");
}

// ✅ 推荐:异步请求链处理
public static CompletableFuture<String> asyncDataProcessing(String apiUrl, String fileUrl) {
// 并行获取数据
CompletableFuture<String> apiFuture = httpClient.sendAsync(
HttpRequest.newBuilder().uri(URI.create(apiUrl)).build(),
HttpResponse.BodyHandlers.ofString()
).thenApply(HttpResponse::body);

CompletableFuture<String> fileFuture = httpClient.sendAsync(
HttpRequest.newBuilder().uri(URI.create(fileUrl)).build(),
HttpResponse.BodyHandlers.ofString()
).thenApply(HttpResponse::body);

// 合并处理结果
return apiFuture.thenCombine(fileFuture, (apiData, fileData) -> {
// 处理和合并数据
return "API: " + apiData.length() + " chars, File: " + fileData.length() + " chars";
});
}
}

3. 文件操作的最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// 文件操作最佳实践
public class FileOperationsBestPractices {

// ✅ 推荐:使用Java 11文件方法
public static void modernFileOperations() throws IOException {
Path configPath = Paths.get("config.properties");
Path logPath = Paths.get("app.log");

// 读取配置文件
if (Files.exists(configPath)) {
String config = Files.readString(configPath, StandardCharsets.UTF_8);
System.out.println("Config loaded: " + config.length() + " chars");
} else {
// 创建默认配置
Map<String, String> defaultConfig = Map.of(
"app.name", "MyApp",
"app.version", "1.0",
"app.debug", "false"
);

String configContent = defaultConfig.entrySet().stream()
.map(entry -> entry.getKey() + "=" + entry.getValue())
.collect(Collectors.joining("\n"));

Files.writeString(configPath, configContent, StandardCharsets.UTF_8);
}

// 追加日志
String logEntry = String.format("[%s] Operation completed%n",
LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
Files.writeString(logPath, logEntry,
StandardCharsets.UTF_8,
StandardOpenOption.CREATE,
StandardOpenOption.APPEND);
}

// ✅ 推荐:临时文件的安全处理
public static void temporaryFileHandling() throws IOException {
Path tempDir = Files.createTempDirectory("myapp");

try {
// 创建临时文件
Path tempFile = Files.createTempFile(tempDir, "data", ".tmp");
Files.writeString(tempFile, "Temporary data");

// 处理临时文件
String content = Files.readString(tempFile);
System.out.println("Temp file content: " + content);

// 清理临时文件
Files.delete(tempFile);

} finally {
// 清理临时目录
try (Stream<Path> paths = Files.walk(tempDir)) {
paths.sorted(Comparator.reverseOrder())
.forEach(path -> {
try {
Files.delete(path);
} catch (IOException e) {
System.err.println("Failed to delete: " + path);
}
});
}
}
}
}

4. Optional增强的使用建议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// Optional最佳实践
public class OptionalEnhancementBestPractices {

// ✅ 推荐:使用isEmpty()提高可读性
public static void modernOptionalUsage() {
Optional<String> result = getUserInput();

// Java 11方式:更直观
if (result.isEmpty()) {
System.out.println("No input provided");
} else {
System.out.println("Input: " + result.get());
}

// 流畅的链式处理
String processed = result
.filter(input -> !input.isBlank())
.map(String::strip)
.map(String::toLowerCase)
.orElse("default");

System.out.println("Processed: " + processed);
}

// ✅ 推荐:结合Java 11字符串方法
public static void stringOptionalCombination() {
List<Optional<String>> inputs = Arrays.asList(
Optional.of(" Hello "),
Optional.empty(),
Optional.of(""),
Optional.of(" World ")
);

List<String> validInputs = inputs.stream()
.filter(Optional::isPresent) // 过滤空Optional
.map(Optional::get)
.filter(input -> !input.isBlank()) // 使用Java 11 isBlank()
.map(String::strip) // 使用Java 11 strip()
.map(String::toUpperCase)
.collect(Collectors.toList());

System.out.println("Valid inputs: " + validInputs);
}

// ✅ 推荐:错误处理的最佳实践
public static void errorHandlingBestPractices() {
Optional<String> configValue = readConfig("timeout");

// 解析配置值,带错误处理
int timeout = configValue
.filter(value -> !value.isBlank()) // 检查非空
.map(String::strip) // 去除空白
.filter(value -> value.matches("\\d+")) // 检查数字格式
.map(Integer::parseInt)
.filter(timeout -> timeout > 0 && timeout <= 300) // 检查范围
.orElse(30); // 默认值

System.out.println("Timeout: " + timeout + " seconds");
}

// 辅助方法
private static Optional<String> getUserInput() {
// 模拟用户输入
return Math.random() > 0.5 ? Optional.of(" Hello World ") : Optional.empty();
}

private static Optional<String> readConfig(String key) {
// 模拟配置读取
return "timeout".equals(key) ? Optional.of("60") : Optional.empty();
}
}

🎉 结语

Java 11作为Oracle发布周期改革后的第一个LTS版本,成功地找到了功能创新与平台稳定的完美平衡。通过字符串API的全面增强、HTTP客户端的标准化、文件操作的简化以及ZGC等重要特性,Java 11不仅提升了开发者的编程体验,更为现代Java应用的开发和部署奠定了坚实的基础。

字符串API的革命性改进isBlank()lines()strip()repeat()等方法让字符串处理变得更加简单和高效。

HTTP客户端的标准化:成为Java标准库的一部分,提供了现代化的网络通信能力,支持HTTP/2、异步处理和WebSocket。

文件操作的简化readString()writeString()方法大幅减少了文件处理的样板代码。

Optional的增强isEmpty()方法让空值处理更加直观和一致。

Java 11的发布,不仅是技术上的进步,更是Oracle对Java生态系统长期承诺的体现。作为LTS版本,Java 11将在未来8年内为企业级应用提供稳定的支持,同时为后续版本的现代化改进提供了宝贵的经验。

在学习和使用Java 11的过程中,建议大家重点关注以下几个方面

  1. 字符串API:掌握isBlank、lines、strip、repeat等方法的正确使用
  2. HTTP客户端:学习异步编程和错误处理的最佳实践
  3. 文件操作:利用readString和writeString简化文件处理
  4. Optional增强:使用isEmpty()提高代码可读性
  5. ZGC调优:根据应用特点优化垃圾回收性能

Java 11的学习虽然需要适应一些新的API和概念,但它带来的收益是值得的。掌握了这些新特性,你将能够编写出更加现代化、高效和可维护的Java代码!

Happy Coding with Java 11! 🎊