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 客户端和字符串处理方法,为我们处理常见任务提供了更强大的工具。

相关推荐
Kookoos16 分钟前
ABP VNext + Orleans:Actor 模型下的分布式状态管理最佳实践
分布式·后端·c#·.net·.netcore·abp vnext
PWRJOY19 分钟前
Flask 会话管理:从原理到实战,深度解析 session 机制
后端·python·flask
Uranus^24 分钟前
使用Spring Boot和Spring Security结合JWT实现安全的RESTful API
java·spring boot·spring security·jwt·restful api
FAQEW28 分钟前
介绍一下什么是反射(面试题详细讲解)
java·开发语言·反射
是三好1 小时前
并发容器(Collections)
java·多线程·juc
jian110581 小时前
java项目实战、pom.xml配置解释、pojo 普通java对象
java·开发语言·python
述雾学java2 小时前
Spring Boot是什么?MybatisPlus常用注解,LambdaQueryWrapper常用方法
java·spring boot·后端
jinhuazhe20132 小时前
maven 3.0多线程编译提高编译速度
java·maven
xosg2 小时前
HTMLUnknownElement的使用
java·前端·javascript
黎明smaly2 小时前
【C语言】复习~动态内存管理
c语言·开发语言·c++·面试