Java 11 新特性详解与代码示例
Java 11 新特性详解与代码示例
文章目录
- Java 11 新特性详解与代码示例
- 1. 新字符串方法
- 1.1. `isBlank()`
- 1.2. `lines()`
- 1.3. `strip()`、`stripLeading()`、`stripTrailing()`
- 1.4. `repeat(int n)`
- 2. 新文件操作方法
- 2.1. `Files.readString(Path path)`
- 2.2. `Files.writeString(Path path, CharSequence csq)`
- 3. Collection 的 `toArray` 方法
- 4. `Predicate.not`
- 5. Lambda 参数的局部变量语法
- 6. HTTP 客户端 API
- 6.1. 同步 GET 请求
- 6.2. 异步 GET 请求
- 6.3. POST 请求
- 7. 直接运行 Java 文件
- 8. 其他重要特性
- 9. 结论
- 10. 参考资料
Java 11(JDK 11)于 2018 年 9 月发布,是 Java 平台的长期支持(LTS)版本,带来了众多新特性和改进,涵盖了语言特性、标准库更新和 JVM 增强。本文将深入探讨 Java 11 的主要新特性,为每个特性提供详细的代码示例,并对优化现有功能的特性提供对比代码。我们的目标是提供“硬核”、深入的内容,确保读者能够理解每个特性的用途并在实际开发中应用。本文基于 Oracle 官方文档和其他可靠资源,确保信息准确。
1. 新字符串方法
Java 11 为 String
类引入了六个新方法,简化了常见的字符串操作任务。这些方法包括 isBlank()
、lines()
、strip()
、stripLeading()
、stripTrailing()
和 repeat()
。以下逐一介绍每个方法,并提供代码示例和与旧方法的对比。
1.1. isBlank()
isBlank()
方法检查字符串是否为空或仅包含空白字符(包括 Unicode 空白字符)。如果字符串为空或仅包含空白字符,返回 true
;否则返回 false
。
public class IsBlankExample {public static void main(String[] args) {String str1 = "";String str2 = " ";String str3 = "Hello";System.out.println("str1 is blank: " + str1.isBlank()); // trueSystem.out.println("str2 is blank: " + str2.isBlank()); // trueSystem.out.println("str3 is blank: " + str3.isBlank()); // false}
}
与旧方法的对比:在 Java 11 之前,开发者通常使用 str.trim().isEmpty()
来检查字符串是否为空或仅包含空白字符。然而,trim()
会创建一个新字符串,而 isBlank()
直接检查原始字符串,效率更高。
// Java 11 之前
String str = " ";
boolean isBlank = str.trim().isEmpty(); // 创建新字符串,效率较低
System.out.println("str is blank: " + isBlank); // true
使用场景:isBlank()
适用于表单验证、数据清理等场景,检查用户输入是否有效。
1.2. lines()
lines()
方法返回一个 Stream<String>
,包含字符串中由换行符(\n
、\r
或 \r\n
)分隔的各行。这对于处理多行文本非常有用。
import java.util.stream.Stream;public class LinesExample {public static void main(String[] args) {String multiline = "Line 1\nLine 2\nLine 3";Stream<String> lines = multiline.lines();lines.forEach(System.out::println);// 输出:// Line 1// Line 2// Line 3}
}
与旧方法的对比:在 Java 11 之前,通常使用 split("\n")
来分割字符串,但这会一次性创建所有行的数组,对于大字符串可能消耗更多内存。lines()
返回流,支持延迟加载,效率更高。
// Java 11 之前
String multiline = "Line 1\nLine 2\nLine 3";
String[] lines = multiline.split("\n");
for (String line : lines) {System.out.println(line);
}
使用场景:lines()
适合处理日志文件、CSV 文件或其他多行文本数据,结合流 API 可以高效地进行过滤或转换。
1.3. strip()
、stripLeading()
、stripTrailing()
这三个方法用于移除字符串中的空白字符。strip()
移除两端的空白字符,stripLeading()
移除开头的空白字符,stripTrailing()
移除末尾的空白字符。与 trim()
不同,这些方法能处理所有 Unicode 空白字符。
public class StripExample {public static void main(String[] args) {String str = " Hello World ";System.out.println("strip: '" + str.strip() + "'"); // "Hello World"System.out.println("stripLeading: '" + str.stripLeading() + "'"); // "Hello World "System.out.println("stripTrailing: '" + str.stripTrailing() + "'"); // " Hello World"// Unicode 空白字符String strWithUnicode = "\u2000Hello\u2000";System.out.println("trim: '" + strWithUnicode.trim() + "'"); // "\u2000Hello\u2000"System.out.println("strip: '" + strWithUnicode.strip() + "'"); // "Hello"}
}
与旧方法的对比:trim()
仅移除 ASCII 控制字符和空格(代码点 <= \u0020
),而 strip()
能移除所有 Unicode 空白字符(如 \u2000
),功能更强大。
使用场景:这些方法适合处理国际化文本或需要精确控制空白字符的场景。
1.4. repeat(int n)
repeat(n)
方法返回一个新字符串,将原字符串重复 n
次。
public class RepeatExample {public static void main(String[] args) {String str = "Java";System.out.println(str.repeat(3)); // "JavaJavaJava"}
}
与旧方法的对比:在 Java 11 之前,重复字符串通常需要使用循环或 StringBuilder
。
// Java 11 之前
String str = "Java";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 3; i++) {sb.append(str);
}
System.out.println(sb.toString()); // "JavaJavaJava"
使用场景:repeat()
适合生成重复的文本模式,如格式化输出或测试数据生成。
2. 新文件操作方法
Java 11 为 java.nio.file.Files
类添加了 readString
和 writeString
方法,简化了文件读写操作。
2.1. Files.readString(Path path)
readString
方法将文件内容直接读取为字符串。
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.IOException;public class ReadStringExample {public static void main(String[] args) {try {String content = Files.readString(Paths.get("file.txt"));System.out.println(content);} catch (IOException e) {e.printStackTrace();}}
}
与旧方法的对比:在 Java 11 之前,读取文件内容通常需要 Files.readAllBytes
或 Files.readAllLines
。
// Java 11 之前
try {String content = new String(Files.readAllBytes(Paths.get("file.txt")));System.out.println(content);
} catch (IOException e) {e.printStackTrace();
}// 或
try {List<String> lines = Files.readAllLines(Paths.get("file.txt"));String content = String.join("\n", lines);System.out.println(content);
} catch (IOException e) {e.printStackTrace();
}
使用场景:readString
适合读取配置文件、JSON 文件等小型文本文件。
2.2. Files.writeString(Path path, CharSequence csq)
writeString
方法将字符串写入文件。
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.IOException;public class WriteStringExample {public static void main(String[] args) {try {Files.writeString(Paths.get("file.txt"), "Hello World");} catch (IOException e) {e.printStackTrace();}}
}
与旧方法的对比:在 Java 11 之前,写入字符串需要 Files.write
或 BufferedWriter
。
// Java 11 之前
try {Files.write(Paths.get("file.txt"), "Hello World".getBytes());
} catch (IOException e) {e.printStackTrace();
}// 或
try (BufferedWriter writer = Files.newBufferedWriter(Paths.get("file.txt"))) {writer.write("Hello World");
} catch (IOException e) {e.printStackTrace();
}
使用场景:writeString
适合快速写入日志、配置文件等。
3. Collection 的 toArray
方法
Java 11 为 Collection
接口添加了新的默认方法 toArray(IntFunction<T[]> generator)
,允许指定如何创建数组,提高类型安全性和代码简洁性。
import java.util.Arrays;
import java.util.List;public class ToArrayExample {public static void main(String[] args) {List<String> list = Arrays.asList("a", "b", "c");String[] array = list.toArray(String[]::new);System.out.println(Arrays.toString(array)); // [a, b, c]}
}
与旧方法的对比:在 Java 11 之前,toArray
需要显式指定数组类型。
// Java 11 之前
List<String> list = Arrays.asList("a", "b", "c");
String[] array = list.toArray(new String[0]); // 或 new String[list.size()]
System.out.println(Arrays.toString(array)); // [a, b, c]
使用场景:toArray(IntFunction)
适合需要将集合转换为特定类型数组的场景,如数据序列化或与遗留代码交互。
4. Predicate.not
Predicate
接口新增了静态方法 not
,返回给定谓词的否定形式,提高流操作的可读性。
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;public class PredicateNotExample {public static void main(String[] args) {List<String> list = Arrays.asList("a", "", "b", " ");List<String> nonBlank = list.stream().filter(Predicate.not(String::isBlank)).collect(Collectors.toList());System.out.println(nonBlank); // [a, b]}
}
与旧方法的对比:在 Java 11 之前,需要使用 !
运算符。
// Java 11 之前
List<String> list = Arrays.asList("a", "", "b", " ");
List<String> nonBlank = list.stream().filter(s -> !s.isBlank()).collect(Collectors.toList());
System.out.println(nonBlank); // [a, b]
使用场景:Predicate.not
适合在流操作中需要否定谓词的场景,增强代码可读性。
5. Lambda 参数的局部变量语法
Java 11 允许在 Lambda 表达式参数中使用 var
关键字,支持添加注解而无需显式指定类型。
import java.util.function.BiFunction;
import javax.annotation.Nonnull;public class LambdaVarExample {public static void main(String[] args) {BiFunction<String, String, String> concat = (@Nonnull var s1, @Nonnull var s2) -> s1 + s2;System.out.println(concat.apply("Hello, ", "World!")); // Hello, World!}
}
与旧方法的对比:在 Java 11 之前,必须显式指定参数类型。
// Java 11 之前
BiFunction<String, String, String> concat = (@Nonnull String s1, @Nonnull String s2) -> s1 + s2;
System.out.println(concat.apply("Hello, ", "World!")); // Hello, World!
使用场景:var
在 Lambda 参数中适合需要添加注解(如 @Nonnull
)的场景,减少冗余代码。
6. HTTP 客户端 API
Java 11 引入了新的 HTTP 客户端 API(java.net.http
包),支持 HTTP/1.1 和 HTTP/2,以及异步请求,取代了旧的 HttpURLConnection
。
6.1. 同步 GET 请求
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.io.IOException;public class HttpClientGetExample {public static void main(String[] args) {try {HttpClient client = HttpClient.newHttpClient();HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://api.example.com/data")).build();HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());System.out.println("Status: " + response.statusCode());System.out.println("Body: " + response.body());} catch (IOException | InterruptedException e) {e.printStackTrace();}}
}
6.2. 异步 GET 请求
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;public class HttpClientAsyncExample {public static void main(String[] args) {HttpClient client = HttpClient.newHttpClient();HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://api.example.com/data")).build();client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body).thenAccept(System.out::println);}
}
6.3. POST 请求
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.io.IOException;public class HttpClientPostExample {public static void main(String[] args) {try {String json = "{\"key\":\"value\"}";HttpClient client = HttpClient.newHttpClient();HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://api.example.com/post")).header("Content-Type", "application/json").POST(HttpRequest.BodyPublishers.ofString(json)).build();HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());System.out.println("Status: " + response.statusCode());System.out.println("Body: " + response.body());} catch (IOException | InterruptedException e) {e.printStackTrace();}}
}
与旧方法的对比:在 Java 11 之前,使用 HttpURLConnection
进行 HTTP 请求。
import java.net.URL;
import java.net.HttpURLConnection;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;public class HttpUrlConnectionExample {public static void main(String[] args) {try {URL url = new URL("https://api.example.com/data");HttpURLConnection con = (HttpURLConnection) url.openConnection();con.setRequestMethod("GET");int status = con.getResponseCode();BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));String inputLine;StringBuilder content = new StringBuilder();while ((inputLine = in.readLine()) != null) {content.append(inputLine);}in.close();con.disconnect();System.out.println("Status: " + status);System.out.println("Body: " + content.toString());} catch (IOException e) {e.printStackTrace();}}
}
使用场景:新 HTTP 客户端 API 适合现代 Web 应用,支持 REST API 调用、WebSocket 等。
7. 直接运行 Java 文件
Java 11 允许使用 java
命令直接运行单文件 Java 源代码,无需先用 javac
编译。
public class HelloWorld {public static void main(String[] args) {System.out.println("Hello, World!");}
}
保存为 HelloWorld.java
,然后运行:
java HelloWorld.java
输出:
Hello, World!
与旧方法的对比:在 Java 11 之前,需要先编译再运行。
javac HelloWorld.java
java HelloWorld
使用场景:适合快速原型开发、脚本编写或教学。
8. 其他重要特性
以下是 Java 11 的其他值得注意的特性:
- 嵌套访问控制(JEP 181):改进了 JVM 对嵌套类的访问控制,允许直接访问私有成员,无需桥接方法。
- Epsilon 垃圾回收器(JEP 318):实验性无操作垃圾回收器,分配内存但不回收,适合性能测试。
- Z 垃圾回收器(JEP 333):实验性低延迟垃圾回收器,适合大堆应用,暂停时间小于 10ms。
- 飞行记录器(Flight Recorder):原为商业功能,现开源,提供低开销的性能分析。
- 移除的模块:Java EE 和 CORBA 模块已从 JDK 移除,需单独引入依赖。
- 废弃的模块:Nashorn JavaScript 引擎和 Pack200 压缩方案被标记为废弃。
- Unicode 10 支持(JEP 327):支持 Unicode 10.0.0,新增字符和脚本。
- TLS 1.3(JEP 332):支持最新的传输层安全协议,提升安全性和性能。
- 新的加密算法(JEP 329):支持 ChaCha20 和 Poly1305 算法,替代旧的 RC4。
9. 结论
Java 11 作为 LTS 版本,为开发者提供了强大的工具和改进,从字符串和文件操作的简化到现代化的 HTTP 客户端 API,这些特性显著提高了代码质量和开发效率。通过本文的代码示例,开发者可以快速上手这些新功能,并在实际项目中应用。建议开发者尝试将这些特性融入现有项目,以充分利用 Java 11 的优势。
10. 参考资料
- Oracle JDK 11 发行说明
- Baeldung: Java 11 新特性