Java 新特性速查:从 Lambda 到虚拟线程
本文覆盖 Java 8 到 Java 21 的核心新特性,包含 Lambda/Stream/Optional/CompletableFuture/模块化/Record/Sealed/文字块/虚拟线程,每个特性附有代码示例和适用场景说明,供快速查阅。
目录
| 章节 | Java 版本 | 说明 |
|---|---|---|
| Java 8 核心特性 | 8 | Lambda、Stream、Optional、新时间 API |
| Java 9-11 特性 | 9-11 | 模块化、集合工厂方法、var、HTTP Client |
| Java 12-16 特性 | 12-16 | Switch 表达式、文字块、Record、instanceof 增强 |
| Java 17 特性 | 17 LTS | Sealed Class 正式版 |
| Java 21 特性 | 21 LTS | 虚拟线程、Switch 模式匹配、Sequenced Collections |
| 版本特性速查表 | — | 一表总览 |
Java 8 核心特性
Lambda 表达式
// 函数式接口:只有一个抽象方法的接口,可用 Lambda 实现
@FunctionalInterface
interface Greeter {
String greet(String name);
}
// Lambda 写法
Greeter g = name -> "Hello, " + name + "!";
System.out.println(g.greet("Alice")); // Hello, Alice!
// 方法引用(Lambda 的简化写法)
List<String> names = List.of("Bob", "Alice", "Charlie");
names.stream()
.sorted(String::compareToIgnoreCase) // 方法引用
.forEach(System.out::println); // 实例方法引用
常用函数式接口:
| 接口 | 签名 | 说明 |
|---|---|---|
Runnable | () -> void | 无参无返回 |
Supplier<T> | () -> T | 无参有返回 |
Consumer<T> | T -> void | 有参无返回 |
Function<T, R> | T -> R | 有参有返回 |
Predicate<T> | T -> boolean | 断言 |
BiFunction<T, U, R> | (T, U) -> R | 双参有返回 |
Stream API
import java.util.stream.*;
List<String> words = List.of("banana", "apple", "cherry", "avocado");
// 过滤 → 映射 → 排序 → 收集
List<String> result = words.stream()
.filter(w -> w.startsWith("a")) // 过滤
.map(String::toUpperCase) // 映射
.sorted() // 排序
.collect(Collectors.toList());
// [APPLE, AVOCADO]
// 统计操作
long count = words.stream().filter(w -> w.length() > 5).count();
Optional<String> longest = words.stream()
.max(Comparator.comparingInt(String::length));
// 数值流(避免装箱)
int[] nums = {1, 2, 3, 4, 5};
int sum = IntStream.of(nums).sum();
double avg = IntStream.of(nums).average().orElse(0);
// 分组
Map<Integer, List<String>> byLength = words.stream()
.collect(Collectors.groupingBy(String::length));
// 分区(按 boolean)
Map<Boolean, List<String>> partitioned = words.stream()
.collect(Collectors.partitioningBy(w -> w.length() > 5));
// 字符串拼接
String joined = words.stream()
.collect(Collectors.joining(", ", "[", "]"));
// [banana, apple, cherry, avocado]
// flatMap:将多层结构展平
List<List<Integer>> nested = List.of(List.of(1, 2), List.of(3, 4));
List<Integer> flat = nested.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
// [1, 2, 3, 4]
// 并行流(CPU 密集型大数据集)
long parallelSum = LongStream.rangeClosed(1, 1_000_000)
.parallel()
.sum();
Stream 惰性求值:中间操作(filter/map/sorted)不立即执行,终止操作(collect/count/forEach)触发整个管道执行。
Optional
import java.util.Optional;
// 避免 NullPointerException 的容器类
Optional<String> opt = Optional.ofNullable(getValue()); // 可能为 null
// 获取值
String val = opt.orElse("default"); // 有值取值,否则返回默认
String val2 = opt.orElseGet(() -> compute()); // 懒加载默认值
String val3 = opt.orElseThrow(IllegalStateException::new);
// 链式操作
Optional<Integer> len = opt
.filter(s -> s.length() > 3)
.map(String::length);
// 存在时执行
opt.ifPresent(s -> System.out.println(s.toUpperCase()));
// Java 9+:ifPresentOrElse
opt.ifPresentOrElse(
s -> System.out.println("Found: " + s),
() -> System.out.println("Not found")
);
// Java 9+:or(返回另一个 Optional)
Optional<String> fallback = opt.or(() -> Optional.of("fallback"));
新时间 API(java.time)
import java.time.*;
import java.time.format.*;
// 本地日期时间(无时区)
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.of(14, 30, 0);
LocalDateTime dt = LocalDateTime.now();
// 带时区
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
// 格式化
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String str = dt.format(fmt);
LocalDateTime parsed = LocalDateTime.parse("2024-01-15 10:30:00", fmt);
// 日期计算
LocalDate tomorrow = date.plusDays(1);
LocalDate lastMonth = date.minusMonths(1);
long daysBetween = ChronoUnit.DAYS.between(date, tomorrow);
// 时间段
Duration duration = Duration.between(time, LocalTime.now());
Period period = Period.between(date, LocalDate.of(2025, 1, 1));
Java 9-11 特性
模块化系统(Java 9)
// module-info.java(放在 src/ 根目录)
module com.example.myapp {
requires java.base; // 隐式依赖,可省略
requires java.sql; // 声明依赖的模块
requires transitive java.logging; // 传递依赖
exports com.example.api; // 对外暴露的包
exports com.example.util to com.example.client; // 限定导出
opens com.example.model; // 允许反射访问(运行时)
}
模块化主要用于构建大型应用和 JDK 本身的精简化,普通 Spring Boot 项目通常不需要手动编写
module-info.java。
集合工厂方法(Java 9)
// 不可变集合(不支持 null 元素)
List<String> list = List.of("a", "b", "c");
Set<Integer> set = Set.of(1, 2, 3);
Map<String, Integer> map = Map.of("one", 1, "two", 2);
Map<String, Integer> map2 = Map.ofEntries(
Map.entry("one", 1),
Map.entry("two", 2)
);
// 可变集合的不可变视图
List<String> unmodifiable = Collections.unmodifiableList(new ArrayList<>());
var 局部变量类型推断(Java 10)
// var 只能用于局部变量,编译期推断类型
var name = "Alice"; // String
var list = new ArrayList<String>(); // ArrayList<String>
var map = new HashMap<String, Integer>(); // HashMap<String, Integer>
// 在 for-each 中使用
for (var entry : map.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
// 不能用于:字段、方法参数、返回值、Lambda 参数
HTTP Client(Java 11)
import java.net.http.*;
import java.net.URI;
HttpClient client = HttpClient.newHttpClient();
// 同步请求
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/data"))
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());
// 异步请求
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
Java 12-16 特性
Switch 表达式(Java 14 正式)
// 旧写法:switch 语句(容易遗漏 break)
String grade;
switch (score / 10) {
case 10: case 9: grade = "A"; break;
case 8: grade = "B"; break;
default: grade = "F";
}
// 新写法:switch 表达式(箭头语法,无 fall-through)
String grade = switch (score / 10) {
case 10, 9 -> "A";
case 8 -> "B";
case 7 -> "C";
default -> "F";
};
// yield:在代码块中返回值
String result = switch (day) {
case MONDAY, FRIDAY -> "工作日";
case SATURDAY, SUNDAY -> {
System.out.println("周末");
yield "休息日"; // 代码块中用 yield 返回
}
default -> "其他";
};
文字块 Text Block(Java 15 正式)
// 旧写法:多行字符串需要大量转义和拼接
String json = "{\"name\": \"Alice\", \"age\": 30}";
// 文字块:所见即所得,开始分隔符必须单独成行
String json = """
{
"name": "Alice",
"age": 30
}
""";
// 文字块就是字符串,可以调用所有 String 方法
String html = """
<html>
<body>
<h1>%s</h1>
</body>
</html>
""".formatted("Hello World!");
// 编译期处理:
// 1. 换行符统一为 LF
// 2. 删除共享前导空格(结束分隔符的位置决定缩进量)
// 3. 处理转义字符(\s 保留尾部空格,\ 行末取消换行)
Record 档案类(Java 16 正式)
// Record:不可变数据载体,自动生成构造器、getter、equals、hashCode、toString
public record Point(double x, double y) {
// 紧凑构造器(用于参数校验)
public Point {
if (x < 0 || y < 0) throw new IllegalArgumentException("坐标不能为负");
}
// 可以添加自定义方法
public double distance() {
return Math.sqrt(x * x + y * y);
}
// 可以实现接口
}
// 使用
Point p = new Point(3.0, 4.0);
System.out.println(p); // Point[x=3.0, y=4.0]
System.out.println(p.x()); // 3.0(getter 无 get 前缀)
System.out.println(p.distance()); // 5.0
System.out.println(p.equals(new Point(3.0, 4.0))); // true
// Record 不可继承,但可以实现接口
public record Circle(double radius) implements Shape {
@Override
public double area() {
return Math.PI * radius * radius;
}
}
Record vs POJO:Record 天然不可变,适合 DTO、值对象、数据载体;POJO 可变,适合需要修改字段的业务对象。
instanceof 模式匹配(Java 16 正式)
// 旧写法:类型判断 + 强制转换
if (obj instanceof String) {
String s = (String) obj; // 多余的转换
System.out.println(s.length());
}
// 新写法:instanceof 模式匹配,自动绑定变量
if (obj instanceof String s) {
System.out.println(s.length()); // s 直接可用
}
// 结合 &&
if (obj instanceof String s && s.length() > 5) {
System.out.println("长字符串: " + s);
}
Java 17 特性
Sealed Class 封闭类(Java 17 正式)
// 封闭类:限制可以继承它的子类,实现"可穷举的类型层次"
public sealed interface Shape
permits Circle, Rectangle, Triangle {}
// 许可类必须声明自身的扩展性
public record Circle(double radius) implements Shape {} // final(record 默认)
public record Rectangle(double width, double height) implements Shape {}
public non-sealed class Triangle implements Shape { // 解封,允许任意继承
// ...
}
// 封闭类的价值:配合 switch 模式匹配,编译器可检查穷举性
static double area(Shape shape) {
return switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.width() * r.height();
case Triangle t -> /* ... */ 0;
// 无需 default:编译器知道所有子类
};
}
封闭类的扩展性控制:
| 许可类声明 | 含义 |
|---|---|
final | 彻底关闭扩展 |
sealed | 继续受限扩展(需再声明 permits) |
non-sealed | 解封,允许任意继承 |
Java 21 特性
虚拟线程 Virtual Thread(Java 21 正式)
// 虚拟线程:JVM 管理的轻量级线程,可创建百万级,适合 IO 密集型任务
// 底层映射到少量平台线程(OS 线程),IO 阻塞时自动让出平台线程
// 方式一:直接创建
Thread vt = Thread.ofVirtual().start(() ->
System.out.println("Running in: " + Thread.currentThread())
);
vt.join();
// 方式二:使用虚拟线程执行器(推荐)
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 100_000; i++) {
final int id = i;
executor.submit(() -> {
// 模拟 IO 阻塞(不会占用平台线程)
Thread.sleep(Duration.ofMillis(100));
return "task " + id;
});
}
} // try-with-resources 自动 shutdown
// 方式三:命名虚拟线程(便于调试)
Thread.ofVirtual()
.name("worker-", 0) // 生成 worker-0, worker-1, ...
.start(runnable);
虚拟线程 vs 平台线程:
| 维度 | 平台线程 | 虚拟线程 |
|---|---|---|
| 创建成本 | 高(MB 级栈,OS 调度) | 极低(KB 级,JVM 调度) |
| 数量上限 | 数千 | 数百万 |
| 适用场景 | CPU 密集型 | IO 密集型(HTTP/DB/文件) |
| 阻塞行为 | 占用 OS 线程 | 自动让出平台线程 |
注意:虚拟线程不适合 CPU 密集型任务,也不适合使用
synchronized持有锁时阻塞(会 pin 住平台线程),应改用ReentrantLock。
Switch 模式匹配(Java 21 正式)
// switch 支持任意类型的模式匹配
static String describe(Object obj) {
return switch (obj) {
case Integer i when i > 0 -> "正整数: " + i; // when 守卫
case Integer i -> "非正整数: " + i;
case String s -> "字符串,长度: " + s.length();
case null -> "null"; // 显式处理 null
default -> "其他类型: " + obj.getClass().getSimpleName();
};
}
// 配合 Sealed Class,无需 default
sealed interface Shape permits Circle, Rectangle {}
record Circle(double r) implements Shape {}
record Rectangle(double w, double h) implements Shape {}
static double area(Shape s) {
return switch (s) {
case Circle c -> Math.PI * c.r() * c.r();
case Rectangle r -> r.w() * r.h();
// 编译器验证穷举性,无需 default
};
}
Sequenced Collections(Java 21)
// 新接口:SequencedCollection / SequencedSet / SequencedMap
// 统一了"有序集合的首尾操作"
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
list.getFirst(); // "a"(Java 21+)
list.getLast(); // "c"
list.addFirst("z");
list.removeLast();
// SequencedMap
LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
map.put("one", 1);
map.put("two", 2);
map.firstEntry(); // Map.Entry{one=1}
map.lastEntry(); // Map.Entry{two=2}
map.reversed(); // 反转视图
CompletableFuture(Java 8,Java 21 虚拟线程加持)
import java.util.concurrent.CompletableFuture;
// 异步编排(避免回调地狱)
CompletableFuture<String> future = CompletableFuture
.supplyAsync(() -> fetchUserName(userId)) // 异步获取用户名
.thenApply(name -> "Hello, " + name) // 同步转换
.thenCompose(msg -> CompletableFuture // 异步链式
.supplyAsync(() -> sendEmail(msg)))
.exceptionally(ex -> "Error: " + ex.getMessage()); // 异常处理
// 等待结果
String result = future.get();
// 组合多个异步任务
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> "World");
// 全部完成后执行
CompletableFuture<Void> all = CompletableFuture.allOf(f1, f2);
all.thenRun(() -> System.out.println(f1.join() + " " + f2.join()));
// 任意一个完成后执行
CompletableFuture<Object> any = CompletableFuture.anyOf(f1, f2);
版本特性速查表
| Java 版本 | LTS | 核心新特性 |
|---|---|---|
| 8 | LTS | Lambda、Stream API、Optional、新时间 API(java.time)、默认方法、CompletableFuture |
| 9 | — | 模块化(Jigsaw)、JShell、集合工厂方法(List.of)、Stream 增强(takeWhile/dropWhile) |
| 10 | — | var 局部变量类型推断 |
| 11 | LTS | HTTP Client 正式版、String 新方法(strip/isBlank/lines)、Files.readString |
| 12 | — | Switch 表达式(预览) |
| 13 | — | 文字块(预览) |
| 14 | — | Switch 表达式正式版、Record(预览)、instanceof 模式匹配(预览) |
| 15 | — | 文字块正式版、Sealed Class(预览) |
| 16 | — | Record 正式版、instanceof 模式匹配正式版 |
| 17 | LTS | Sealed Class 正式版、移除 Applet API |
| 18 | — | UTF-8 默认编码 |
| 19 | — | 虚拟线程(预览)、结构化并发(孵化) |
| 20 | — | 虚拟线程(第二次预览)、Switch 模式匹配(第四次预览) |
| 21 | LTS | 虚拟线程正式版、Switch 模式匹配正式版、Sequenced Collections、字符串模板(预览) |
参考资料
评论 (0)