JDK 11 新特性详解
JDK 11 新特性详解
JDK 11 于2018年9月25日正式发布,是继 JDK 8 之后的第二个长期支持(LTS)版本,也是 Oracle 改变 JDK 许可模式后的第一个版本。JDK 11 包含大量重要特性:Lambda 参数 var、String 新方法、正式 HTTP Client API、Flight Recorder、ZGC、Epsilon GC、单文件源码启动、TLS 1.3 支持等,是一次内容极其丰富的 LTS 升级。
目录
- Lambda 参数 var 注解
- String 新方法
- 文件读写新方法
- 集合新方法
- Optional 新方法
- HTTP Client API(正式)
- Launch Single-File Source Code
- Flight Recorder(JFR)
- ZGC(实验性)
- Epsilon GC
- Shenandoah GC(实验性)
- TLS 1.3 支持
- Unicode 10 支持
- 移除 Java EE 和 CORBA 模块
- Nashorn JavaScript 引擎废弃
- 动态 CDS 归档
- 其他重要特性
- JDK 11 特性总览表
1. Lambda 参数 var 注解
1.1 概述
JDK 11 允许在 Lambda 表达式的参数上使用var关键字(JEP 323),主要目的是让开发者能够为 Lambda 参数添加注解。
核心规则:
- 所有 Lambda 参数必须同时使用
var或同时不使用 - 不能混合使用
var和显式类型 var在 Lambda 中仅用于注解,类型推断行为不变
1.2 代码案例
// ============ 1. Lambda 参数使用 var ============// JDK 10 及之前:无法为 Lambda 参数添加注解// (s) -> s.length() // 无法添加 @NonNull 等注解// JDK 11:可以为 Lambda 参数添加注解(@NonNullvars)->s.length()// 多个参数(varx,vary)->x+y// ============ 2. 注解示例 ============importjava.lang.annotation.*;@Target(ElementType.TYPE_USE)@Retention(RetentionPolicy.RUNTIME)@interfaceNonNull{}@Target(ElementType.TYPE_USE)@Retention(RetentionPolicy.RUNTIME)@interfaceEmail{}// 使用注解List<String>names=List.of("Alice","Bob","Charlie");// 为 Lambda 参数添加注解names.stream().map((@NonNullvarname)->name.toUpperCase()).forEach(System.out::println);// 多个参数names.stream().sorted((@NonNullvara,@NonNullvarb)->a.compareTo(b)).forEach(System.out::println);// ============ 3. 规则:必须统一使用 var ============// ✅ 正确:全部使用 var(varx,vary)->x+y// ✅ 正确:全部不使用 var(x,y)->x+y// ❌ 错误:混合使用// (var x, y) -> x + y // 编译报错// (var x, String y) -> x + y // 编译报错// ============ 4. 实际应用场景 ============// 静态分析工具(如 Checker Framework)List<String>inputs=List.of("hello","world");List<Integer>lengths=inputs.stream().map((@NonNullvars)->s.length()).collect(Collectors.toList());// 自定义验证inputs.stream().filter((@Emailvaremail)->email.contains("@")).forEach(System.out::println);// ============ 5. 对比方法引用 ============// 当不需要注解时,方法引用更简洁names.stream().map(String::toUpperCase)// 推荐.forEach(System.out::println);// 需要注解时才使用 varnames.stream().map((@NonNullvars)->s.toUpperCase()).forEach(System.out::println);2. String 新方法
2.1 概述
JDK 11 为String类新增了多个实用方法(JEP 329 的一部分),大幅增强了字符串处理能力。
新增方法一览:
| 方法 | 说明 |
|---|---|
isBlank() | 判断是否为空或只包含空白字符 |
lines() | 按行分割为 Stream |
strip() | 去除首尾空白(支持 Unicode) |
stripLeading() | 去除首部空白 |
stripTrailing() | 去除尾部空白 |
repeat(int) | 重复字符串指定次数 |
2.2 代码案例
// ============ 1. isBlank() — 判断是否为空或只包含空白 ============"".isBlank();// true" ".isBlank();// true(空格)"\t\n".isBlank();// true(制表符+换行)" a ".isBlank();// false"hello".isBlank();// false// 对比 isEmpty()"".isEmpty();// true" ".isEmpty();// false(有空格,不为空)" ".isBlank();// true(但全是空白)// 实际应用:验证用户输入StringuserInput=" ";if(userInput.isBlank()){System.out.println("输入不能为空或只包含空白");}// ============ 2. lines() — 按行分割为 Stream ============Stringmultiline="line1\nline2\nline3\nline4";// 返回 Stream<String>List<String>lines=multiline.lines().collect(Collectors.toList());// ["line1", "line2", "line3", "line4"]// 支持 \n, \r, \r\nStringmixed="line1\nline2\rline3\r\nline4";mixed.lines().forEach(System.out::println);// 实际应用:处理多行配置Stringconfig=""" server.host=localhost server.port=8080 server.timeout=30 """;Map<String,String>configMap=config.lines().filter(line->!line.isBlank()).map(line->line.split("=",2)).filter(parts->parts.length==2).collect(Collectors.toMap(parts->parts[0].trim(),parts->parts[1].trim()));// {server.host=localhost, server.port=8080, server.timeout=30}// 实际应用:过滤空行Stringtext="Hello\n\nWorld\n\nJava";List<String>nonEmptyLines=text.lines().filter(line->!line.isBlank()).collect(Collectors.toList());// ["Hello", "World", "Java"]// ============ 3. strip() — 去除首尾空白(Unicode 感知) ============// strip() 去除所有 Unicode 空白字符" hello ".strip();// "hello""\t hello \n".strip();// "hello""\u2000hello\u2000".strip();// "hello"(Unicode 空白)// stripLeading() — 只去除首部" hello ".stripLeading();// "hello "// stripTrailing() — 只去除尾部" hello ".stripTrailing();// " hello"// 对比 trim()// trim() 只去除 ASCII 空白(code <= U+0020)// strip() 去除所有 Unicode 空白(Character.isWhitespace)StringunicodeSpace="\u2000hello\u2000";// Unicode 空白unicodeSpace.trim();// "\u2000hello\u2000"(不去除,不是 ASCII 空白)unicodeSpace.strip();// "hello"(去除,是 Unicode 空白)// 实际应用:清理用户输入StringrawInput=" \t Alice \n";StringcleanInput=rawInput.strip();// "Alice"// ============ 4. repeat(int) — 重复字符串 ============"ha".repeat(3);// "hahaha""-".repeat(10);// "----------""abc".repeat(0);// ""(重复0次为空)"hello".repeat(1);// "hello"(重复1次不变)// 实际应用:生成表格分隔线intwidth=50;Stringseparator="=".repeat(width);// "=================================================="// 实际应用:生成缩进intindent=4;Stringindentation=" ".repeat(indent);// " "// 实际应用:生成进度条intprogress=7;inttotal=10;Stringbar="█".repeat(progress)+"░".repeat(total-progress);// "███████░░░"// 实际应用:填充字符串到固定长度StringpadRight(Strings,intlength){returns+" ".repeat(Math.max(0,length-s.length()));}StringpadLeft(Strings,intlength){return" ".repeat(Math.max(0,length-s.length()))+s;}// ============ 5. 综合应用 ============// 处理 CSV 文件Stringcsv=""" name,age,city Alice,25,Beijing Bob,30,Shanghai Charlie,20,Guangzhou """;List<Map<String,String>>records=csv.lines().filter(line->!line.isBlank())// 过滤空行.skip(1)// 跳过表头.map(line->line.split(",")).filter(parts->parts.length==3).map(parts->Map.of("name",parts[0].strip(),