Java 11 新特性详解与实践

前言

Java 11 于 2018 年 9 月发布,是继 Java 8 之后的又一个长期支持版本(LTS)。

1. 字符串增强

Java 11 为 String 类增加了多个实用方法,大大简化了字符串处理。

1.1 strip() 系列方法

相比 trim(),新的 strip() 方法可以处理 Unicode 空白字符。

arduino 复制代码
// 移除字符串首尾的空白符
String text = "  Hello Java 11!  ";
System.out.println("使用trim(): [" + text.trim() + "]");      // [Hello Java 11!]
System.out.println("使用strip(): [" + text.strip() + "]");    // [Hello Java 11!]

// 仅移除开头的空白符
System.out.println("使用stripLeading(): [" + text.stripLeading() + "]");  // [Hello Java 11!  ]

// 仅移除结尾的空白符
System.out.println("使用stripTrailing(): [" + text.stripTrailing() + "]");  // [  Hello Java 11!]

对于包含 Unicode 空白字符的情况,strip() 的优势更加明显:

csharp 复制代码
String textWithUnicode = "\u2005Hello Java 11!\u2005";
System.out.println("使用trim(): [" + textWithUnicode.trim() + "]");    // 不能正确处理 Unicode 空白
System.out.println("使用strip(): [" + textWithUnicode.strip() + "]");  // 正确处理 Unicode 空白

1.2 isBlank() 方法

判断字符串是否为空或仅包含空白字符:

ini 复制代码
String empty = "";
String blank = "   \t   \n ";
String notBlank = "Java";

System.out.println(empty.isBlank());    // true
System.out.println(blank.isBlank());    // true
System.out.println(notBlank.isBlank()); // false

1.3 lines() 方法

将字符串按行分割并返回流:

arduino 复制代码
String multiLine = "Java\n11\nFeatures";
multiLine.lines().forEach(System.out::println);
// 输出:
// Java
// 11
// Features

// 结合其他 Stream 操作使用
long lineCount = multiLine.lines().count();
System.out.println("行数: " + lineCount);  // 3

1.4 repeat() 方法

将字符串重复指定次数:

arduino 复制代码
String str = "Java";
System.out.println(str.repeat(3));  // JavaJavaJava

// 创建分隔线
String dash = "-";
System.out.println(dash.repeat(50));  // 输出 50 个连字符

// 创建缩进
String createIndent(int level) {
    return " ".repeat(level * 2);
}
System.out.println(createIndent(2) + "Hello"); // "    Hello"

2. 集合增强

2.1 Collection.toArray(IntFunction)

新的 toArray 方法允许更简洁地将集合转换为指定类型的数组:

ini 复制代码
List<String> list = List.of("Java", "11", "Features");

// Java 8 方式
String[] array1 = list.toArray(new String[0]);

// Java 11 方式 - 使用数组构造器引用
String[] array2 = list.toArray(String[]::new);

// 使用其他类型
Integer[] numbers = List.of(1, 2, 3).toArray(Integer[]::new);

3. Lambda 参数的局部变量语法

Java 11 允许在 Lambda 表达式的参数中使用 var 关键字,增强代码的一致性并允许添加注解:

less 复制代码
// 不使用 var
Consumer<String> consumer1 = (String s) -> System.out.println(s);

// 使用 var
Consumer<String> consumer2 = (var s) -> System.out.println(s);

// var 的主要优势:可以添加注解
import java.util.Objects;
Consumer<String> consumer3 = (@NotNull var s) -> System.out.println(s);

// 多参数示例
BiFunction<String, String, Integer> comparator =
    (@NotNull var s1, @NotNull var s2) -> s1.compareTo(s2);

4. 标准 HTTP 客户端 API

Java 11 将 HTTP 客户端 API标准化,并放在 java.net.http 包中。

4.1 基本用法

arduino 复制代码
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

// 创建客户端
HttpClient client = HttpClient.newBuilder()
    .version(HttpClient.Version.HTTP_2)  // 默认使用 HTTP/2
    .connectTimeout(Duration.ofSeconds(10))
    .build();

// 创建请求
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.github.com/users/octocat"))
    .header("Accept", "application/json")
    .GET()  // GET 是默认方法,可以省略
    .build();

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

// 处理响应
System.out.println("状态码: " + response.statusCode());
System.out.println("响应体: " + response.body());

4.2 异步请求

scss 复制代码
// 使用相同的 client 和 request

// 发送异步请求
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
    .thenApply(HttpResponse::body)
    .thenAccept(System.out::println)
    .join();  // 等待完成

4.3 POST 请求

less 复制代码
// 创建 POST 请求
HttpRequest postRequest = HttpRequest.newBuilder()
    .uri(URI.create("https://postman-echo.com/post"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{"name":"Java 11"}"))
    .build();

// 发送请求
HttpResponse<String> postResponse = client.send(
    postRequest,
    HttpResponse.BodyHandlers.ofString()
);

System.out.println("POST 响应: " + postResponse.body());

4.4 处理不同类型的响应体

ini 复制代码
// 获取字节数组响应
HttpResponse<byte[]> binaryResponse = client.send(
    request,
    HttpResponse.BodyHandlers.ofByteArray()
);

// 获取输入流
HttpResponse<InputStream> streamResponse = client.send(
    request,
    HttpResponse.BodyHandlers.ofInputStream()
);

// 直接将响应保存到文件
HttpResponse<Path> fileResponse = client.send(
    request,
    HttpResponse.BodyHandlers.ofFile(Paths.get("response.json"))
);

4.5 配置 WebSocket

typescript 复制代码
// WebSocket 客户端
HttpClient webSocketClient = HttpClient.newHttpClient();

WebSocket webSocket = webSocketClient.newWebSocketBuilder()
    .buildAsync(URI.create("wss://echo.websocket.org"), new WebSocket.Listener() {
        @Override
        public void onOpen(WebSocket webSocket) {
            System.out.println("WebSocket 连接已打开");
            webSocket.request(1);
        }

        @Override
        public CompletionStage<?> onText(WebSocket webSocket,
                                         CharSequence message,
                                         boolean last) {
            System.out.println("接收到消息: " + message);
            webSocket.request(1);
            return CompletableFuture.completedFuture(null);
        }

        @Override
        public CompletionStage<?> onClose(WebSocket webSocket,
                                          int statusCode,
                                          String reason) {
            System.out.println("WebSocket 已关闭: " + reason);
            return CompletableFuture.completedFuture(null);
        }
    }).join();

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

5. 单文件源代码程序

Java 11 允许直接运行单个源代码文件,无需先编译为 class 文件。这对于简单脚本和原型开发非常有用。

5.1 基本用法

创建 HelloJava11.java 文件:

csharp 复制代码
// 无需 public class 声明
// 文件名可以与类名不匹配
void main() {
    System.out.println("Hello Java 11!");

    // 直接使用 Java 11 的新特性
    var text = "  Java 11  ";
    System.out.println(text.strip());
}

直接运行:

复制代码
java HelloJava11.java

6. 其他 API 改进

6.1 Optional 增强

arduino 复制代码
import java.util.Optional;

// 当值不存在时执行操作
Optional<String> optional = Optional.empty();
optional.ifPresentOrElse(
    value -> System.out.println("值: " + value),
    () -> System.out.println("值不存在")
);  // 输出: 值不存在

// 如果为空则返回备选的 Optional
Optional<String> result = optional.or(() -> Optional.of("默认值"));
System.out.println(result.get());  // 输出: 默认值

// 转换为 Stream
Optional<String> optional2 = Optional.of("Java");
optional2.stream().forEach(System.out::println);  // 输出: Java

6.2 Files 类新方法

arduino 复制代码
import java.nio.file.Files;
import java.nio.file.Path;

// 读取文件内容为字符串
String content = Files.readString(Path.of("file.txt"));

// 写入字符串到文件
Files.writeString(Path.of("output.txt"), "Hello Java 11");

// 判断两个文件是否相同
boolean isSame = Files.mismatch(Path.of("file1.txt"), Path.of("file2.txt")) == -1;

6.3 Path 改进

ini 复制代码
import java.nio.file.Path;

// 转换 String 为 Path 的简化方法
Path path = Path.of("/home", "user", "docs");
Path path2 = Path.of(URI.create("file:///home/user/docs"));

6.4 Predicate 接口新方法

ini 复制代码
import java.util.function.Predicate;
import java.util.List;

List<String> list = List.of("Java", "", "11", null, "Features");

// 返回不满足原始条件的 Predicate
Predicate<String> isNotBlank = Predicate.not(String::isBlank);

// 过滤非空且非空白的字符串
list.stream()
    .filter(Objects::nonNull)
    .filter(isNotBlank)
    .forEach(System.out::println);

7. 总结

Java 11 作为长期支持版本,提供了大量实用的新特性和改进,包括字符串处理增强、标准 HTTP 客户端、单文件源代码执行等,同时在性能、安全性和开发体验方面也有显著提升。

作为 Java 开发人员,熟练掌握这些新特性将帮助我们编写更简洁、高效的代码,并提高开发效率。特别是标准 HTTP 客户端和字符串处理方法,为我们处理常见任务提供了更强大的工具。

相关推荐
dokii18 分钟前
leetcode572 另一棵树的子树
java·开发语言·算法
江沉晚呤时14 分钟前
深入探析C#设计模式:访问者模式(Visitor Pattern)的原理与应用
java·服务器·开发语言·数据库·.netcore
橘猫云计算机设计31 分钟前
基于php的成绩分析和预警与预测网站(源码+lw+部署文档+讲解),源码可白嫖!
开发语言·后端·信息可视化·毕业设计·php
@西瓜@37 分钟前
JAVAEE(多线程)
java·开发语言
代码代码快快显灵1 小时前
java之file和IO流
java·开发语言
Java小陆1 小时前
Java基础-Collection单列集合
后端
一只拉古1 小时前
掌握贪心(Greedy)算法:从 LeetCode 难题到系统架构
算法·leetcode·面试
Java小陆1 小时前
Java基础--正则表达式
后端
枫super1 小时前
Servlet、HTTP与Spring Boot Web全面解析与整合指南
spring boot·后端·http·servlet·java-ee·idea·javase
张哈大1 小时前
lombok注解不起作用
后端