1.7+新特性
约 7633 字大约 25 分钟
2026-05-05
从 Java 7 到 Java 21+,Java 语言和平台经历了巨大的变革。本文按版本梳理各版本的核心新特性。
一、Java 7(2011.07)
代号 Dolphin,是 Oracle 收购 Sun 后的第一个大版本。
1.1 switch 支持字符串
String day = "MONDAY";
switch (day) {
case "MONDAY":
System.out.println("星期一");
break;
case "TUESDAY":
System.out.println("星期二");
break;
default:
System.out.println("其他");
}原理:编译器将 switch(String) 转换为先对 hashCode() 的 switch,再用 equals() 二次判断,本质上还是 switch(int)。
1.2 try-with-resources(自动资源管理)
实现了 AutoCloseable 接口的资源会在 try 块结束时自动调用 close()。
// 旧写法
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("test.txt"));
String line = br.readLine();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try { br.close(); } catch (IOException e) { e.printStackTrace(); }
}
}
// Java 7 新写法
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
String line = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
// br.close() 自动调用,无需 finally
// 多个资源
try (FileInputStream fis = new FileInputStream("in.txt");
FileOutputStream fos = new FileOutputStream("out.txt")) {
// 读写操作
} catch (IOException e) {
e.printStackTrace();
}注意:资源关闭顺序与声明顺序相反(后声明先关闭)。
Java 9 增强:可以用已有的 final/effectively final 变量:
BufferedReader br = new BufferedReader(new FileReader("test.txt"));
try (br) { // Java 9+
String line = br.readLine();
}1.3 泛型类型推断(钻石操作符)
// Java 7 之前
Map<String, List<String>> map = new HashMap<String, List<String>>();
// Java 7 — 右侧可省略类型参数
Map<String, List<String>> map = new HashMap<>();Java 9 增强:匿名内部类也支持钻石操作符:
// Java 9+
List<String> list = new ArrayList<>() {
{ add("a"); add("b"); }
};1.4 多异常捕获(multi-catch)
// 旧写法
try {
// ...
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
// Java 7 — 一个 catch 捕获多个异常
try {
// ...
} catch (IOException | SQLException e) {
e.printStackTrace();
}
// 注意:多 catch 中的异常变量 e 是隐式 final 的,不可重新赋值1.5 数字字面量增强
// 二进制字面量
int binary = 0b1101; // 13
byte b = 0b0010_1010; // 42
// 下划线分隔
int million = 1_000_000;
long hex = 0xCAFE_BABE;
double pi = 3.141_592_654;
// 注意:_ 不能放在开头、结尾、小数点两边、进制标识两边1.6 NIO.2(java.nio.file)
新增 Path、Paths、Files 工具类,极大简化文件 I/O。
// 创建 Path
Path path = Paths.get("/home/user/test.txt");
// 读取文件所有行
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
// 复制文件
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
// 遍历目录
try (Stream<Path> stream = Files.walk(Paths.get("/home/user"), 2)) {
stream.filter(Files::isRegularFile)
.forEach(System.out::println);
}
// 文件变更通知(WatchService)
WatchService watchService = FileSystems.getDefault().newWatchService();
path.getParent().register(watchService, StandardOpenOption.WRITE);1.7 Fork/Join 框架
用于并行执行任务的框架,核心是工作窃取算法。
// 计算 1+2+...+n 的 ForkJoinTask
class SumTask extends RecursiveTask<Long> {
private static final int THRESHOLD = 10;
private long start, end;
public SumTask(long start, long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if (end - start <= THRESHOLD) {
long sum = 0;
for (long i = start; i <= end; i++) sum += i;
return sum;
}
long mid = (start + end) / 2;
SumTask left = new SumTask(start, mid);
SumTask right = new SumTask(mid + 1, end);
left.fork(); // 异步执行左任务
return right.compute() + left.join();
}
}
ForkJoinPool pool = new ForkJoinPool();
Long result = pool.invoke(new SumTask(1, 100));1.8 其他
Objects工具类:Objects.equals(a, b)、Objects.requireNonNull(obj, "msg")ThreadLocalRandom:并发场景下的随机数生成器- 方法句柄(MethodHandle):比反射更轻量的方法调用机制(JSR 292)
@SafeVarargs注解:抑制泛型可变参数警告
二、Java 8(2014.03 LTS)
Java 历史上变化最大的版本,彻底改变了 Java 的编程风格。
2.1 Lambda 表达式
Lambda 本质是一段可传递的匿名函数,使代码更简洁。
// 语法:(参数列表) -> { 方法体 }
// 无参
Runnable r = () -> System.out.println("Hello");
// 单参(可省略括号)
Consumer<String> c = s -> System.out.println(s);
// 多参
Comparator<Integer> comp = (a, b) -> a - b;
// 多行方法体
BinaryOperator<Integer> add = (a, b) -> {
int result = a + b;
return result;
};使用前提:接口必须是函数式接口(只有一个抽象方法的接口)。
2.2 函数式接口
常用函数式接口位于 java.util.function 包:
| 接口 | 抽象方法 | 说明 |
|---|---|---|
Consumer<T> | void accept(T t) | 消费者,有入无出 |
Supplier<T> | T get() | 供给者,无入有出 |
Function<T, R> | R apply(T t) | 函数,有入有出 |
Predicate<T> | boolean test(T t) | 断言,返回 boolean |
BiFunction<T,U,R> | R apply(T t, U u) | 双参数函数 |
UnaryOperator<T> | T apply(T t) | 一元运算(入出同类型) |
BinaryOperator<T> | T apply(T t1, T t2) | 二元运算 |
// Consumer — 消费一个值
Consumer<String> printer = s -> System.out.println(s);
printer.accept("Hello World");
// Supplier — 提供一个值
Supplier<Double> random = () -> Math.random();
System.out.println(random.get());
// Function — 转换
Function<String, Integer> len = s -> s.length();
System.out.println(len.apply("abc")); // 3
// Predicate — 判断
Predicate<String> isEmpty = s -> s == null || s.isEmpty();
System.out.println(isEmpty.test("")); // true
Predicate<String> notEmpty = isEmpty.negate(); // 取反
// 链式调用
Function<Integer, Integer> f1 = x -> x + 1;
Function<Integer, Integer> f2 = x -> x * 2;
System.out.println(f1.andThen(f2).apply(3)); // (3+1)*2 = 8
System.out.println(f1.compose(f2).apply(3)); // 3*2+1 = 72.3 方法引用与构造器引用
方法引用是 Lambda 的简写形式。
// 四种形式:
// 1. 对象::实例方法
Consumer<String> c = System.out::println;
// 2. 类::静态方法
BinaryOperator<Double> max = Math::max;
Comparator<Integer> comp = Integer::compare;
// 3. 类::实例方法(第一个参数作为调用者)
Function<String, Integer> len = String::length;
BiPredicate<String, String> eq = String::equals;
// 4. 构造器引用
Supplier<ArrayList<String>> supplier = ArrayList::new;
Function<Integer, ArrayList<String>> withCap = ArrayList::new;2.4 Stream API
Stream 是 Java 8 的核心亮点,提供声明式的数据处理能力。
特点:
- 不存储数据,只是对数据源(集合、数组等)的包装
- 惰性求值:中间操作不立即执行,遇到终止操作才执行
- 不可重复使用:一个 Stream 只能消费一次
- 并行处理:
parallelStream()利用 ForkJoinPool 并行执行
List<String> list = Arrays.asList("Java", "Python", "Go", "Rust", "C++");
// 中间操作(返回 Stream)
list.stream()
.filter(s -> s.length() > 2) // 过滤
.map(String::toUpperCase) // 映射
.sorted() // 排序
.distinct() // 去重
.limit(3) // 截取
.skip(1) // 跳过
.peek(System.out::println); // 调试(窥视)
// 终止操作(返回结果或副作用)
list.stream()
.filter(s -> s.startsWith("J"))
.collect(Collectors.toList()); // 收集为 List
long count = list.stream().count(); // 计数
boolean allMatch = list.stream().allMatch(s -> s.length() > 0); // 全匹配
boolean anyMatch = list.stream().anyMatch(s -> s.contains("a")); // 任一匹配
Optional<String> first = list.stream().findFirst(); // 第一个元素
list.stream().forEach(System.out::println); // 遍历
// 数值流 — 避免装箱开销
IntStream.range(1, 100).sum();
DoubleStream.of(1.0, 2.0, 3.0).average();Collectors 常用收集器:
// toList / toSet / toMap
List<String> result = stream.collect(Collectors.toList());
Set<String> set = stream.collect(Collectors.toSet());
Map<String, Integer> map = stream.collect(
Collectors.toMap(User::getName, User::getAge));
// 分组
Map<String, List<User>> byCity = users.stream()
.collect(Collectors.groupingBy(User::getCity));
Map<String, Long> countByCity = users.stream()
.collect(Collectors.groupingBy(User::getCity, Collectors.counting()));
// 分区(分两组:true/false)
Map<Boolean, List<User>> partition = users.stream()
.collect(Collectors.partitioningBy(u -> u.getAge() >= 18));
// 连接字符串
String joined = stream.collect(Collectors.joining(", ", "[", "]"));
// 统计
IntSummaryStatistics stats = list.stream()
.collect(Collectors.summarizingInt(String::length));
System.out.println(stats.getMax() + ", " + stats.getAverage());
// reducing — 归约
int sum = stream.collect(Collectors.reducing(0, String::length, Integer::sum));
// mapping / flatMapping — 映射收集(Java 9+)
List<String> allTags = articles.stream()
.collect(Collectors.flatMapping(a -> a.getTags().stream(), Collectors.toList()));map 与 flatMap:
// map — 一对一映射
List<String> words = Arrays.asList("Hello", "World");
List<Integer> lengths = words.stream()
.map(String::length)
.collect(Collectors.toList()); // [5, 5]
// flatMap — 一对多映射并展平
List<List<String>> nested = Arrays.asList(
Arrays.asList("a", "b"),
Arrays.asList("c", "d")
);
List<String> flat = nested.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList()); // [a, b, c, d]reduce 归约:
// reduce — 将流中元素反复结合,得到最终值
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
// 有初始值
int sum = nums.stream().reduce(0, (a, b) -> a + b); // 15
int sum2 = nums.stream().reduce(0, Integer::sum); // 同上
// 无初始值(返回 Optional)
Optional<Integer> max = nums.stream().reduce(Integer::max);
// 并行时的三参数 reduce
int parallelSum = nums.parallelStream()
.reduce(0, Integer::sum, Integer::sum);2.5 Optional
优雅地处理 null 值,避免 NPE。
// 创建
Optional<String> opt1 = Optional.of("hello"); // 非 null
Optional<String> opt2 = Optional.ofNullable(null); // 可为 null
Optional<String> opt3 = Optional.empty(); // 空 Optional
// 判断
if (opt1.isPresent()) { /* 有值 */ }
opt1.ifPresent(System.out::println);
// 获取
String val = opt1.get(); // 无值抛异常(不推荐)
String val2 = opt1.orElse("default"); // 有则返回,无则默认
String val3 = opt1.orElseGet(() -> expensiveDefault());// 惰性默认
String val4 = opt1.orElseThrow(() -> new RuntimeException("无值"));
// 转换
Optional<Integer> len = opt1.map(String::length);
Optional<Integer> flat = opt1.flatMap(s -> Optional.of(s.length()));
// 过滤
Optional<String> filtered = opt1.filter(s -> s.length() > 3);
// Java 9+:or() — 链式备选
Optional<String> result = opt1.or(() -> Optional.of("fallback"));
// Java 9+:ifPresentOrElse()
opt1.ifPresentOrElse(
v -> System.out.println("有值:" + v),
() -> System.out.println("无值")
);2.6 接口默认方法和静态方法
接口中可以定义具有方法体的默认方法和静态方法。
interface Vehicle {
// 抽象方法
void run();
// 默认方法(子类可重写)
default void start() {
System.out.println("Vehicle starting...");
}
// 静态方法
static Vehicle create(String type) {
return new Car();
}
}
// 多继承冲突解决
interface A {
default void hello() { System.out.println("A"); }
}
interface B {
default void hello() { System.out.println("B"); }
}
class C implements A, B {
@Override
public void hello() {
A.super.hello(); // 指定调用 A 的默认方法
}
}原则(三定律):
- 类优先于接口(类中的方法优先级最高)
- 子接口优先于父接口
- 类/接口冲突时,必须手动指定
接口名.super.方法名()
2.7 新日期时间 API(java.time)
线程安全、不可变、API 清晰,彻底替代 Date 和 Calendar。
// 基础类(不可变、线程安全)
LocalDate date = LocalDate.now(); // 2026-05-05
LocalTime time = LocalTime.now(); // 14:30:00.123
LocalDateTime dt = LocalDateTime.now(); // 2026-05-05T14:30:00.123
// 创建指定时间
LocalDate d = LocalDate.of(2026, 5, 5);
LocalTime t = LocalTime.of(14, 30, 0);
// 从字符串解析
LocalDate parsed = LocalDate.parse("2026-05-05");
// 日期运算(plus / minus)
LocalDate tomorrow = LocalDate.now().plusDays(1);
LocalDate lastMonth = LocalDate.now().minusMonths(1);
LocalDate nextMonday = LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.MONDAY));
LocalDate firstDayOfMonth = LocalDate.now().withDayOfMonth(1);
// 时间间隔
Period period = Period.between(start, end); // 日期差
Duration duration = Duration.between(time1, time2); // 时间差
// 时间戳及带时区的时间
Instant instant = Instant.now(); // UTC 时间戳
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
OffsetDateTime odt = OffsetDateTime.now(ZoneOffset.of("+8"));
// 格式化
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String str = LocalDateTime.now().format(fmt);
LocalDateTime parsed = LocalDateTime.parse("2026-05-05 14:30:00", fmt);
// 获取时间戳毫秒数
long millis = Instant.now().toEpochMilli();
long millis2 = System.currentTimeMillis(); // 传统方式,等价2.8 CompletableFuture(异步编程增强)
让异步编程更简洁,支持链式调用和组合。
// 异步执行(无返回值)
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
// 耗时操作
});
// 异步执行(有返回值)
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
return queryFromDB(); // 耗时查询
});
// 链式处理:thenApply / thenAccept / thenRun
future.thenApply(result -> result.toUpperCase()) // 转换结果
.thenAccept(System.out::println) // 消费结果
.thenRun(() -> System.out.println("完成")); // 不关心前面结果
// 组合:thenCombine / thenCompose
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<String> combined = f1.thenCombine(f2, (a, b) -> a + " " + b);
// 等待所有完成
CompletableFuture<Void> all = CompletableFuture.allOf(f1, f2, f3);
// 任一完成
CompletableFuture<Object> any = CompletableFuture.anyOf(f1, f2, f3);
// 异常处理
future.exceptionally(ex -> {
System.out.println("出错:" + ex.getMessage());
return "默认值";
});
// handle — 无论正常还是异常都执行
future.handle((result, ex) -> {
if (ex != null) return "出错";
return result.toUpperCase();
});
// 阻塞获取结果
String result = future.get(); // 一直等
String result = future.get(5, TimeUnit.SECONDS); // 限时等待2.9 Base64 编码
String encoded = Base64.getEncoder().encodeToString("hello".getBytes());
byte[] decoded = Base64.getDecoder().decode(encoded);
// URL 安全编码
String urlEncoded = Base64.getUrlEncoder().encodeToString(data);2.10 类型注解与重复注解
// 类型注解 — 注解可以用在任何用到类型的地方
@NotNull String name;
List<@NonNull String> list;
// 重复注解
@Repeatable(Authors.class)
@interface Author {
String name();
}
@interface Authors {
Author[] value();
}
@Author(name = "张三")
@Author(name = "李四")
class Book {}2.11 PermGen 移除
- HotSpot 移除了永久代(PermGen),改用元空间(Metaspace)
- 元空间使用本地内存,默认无上限(受系统内存限制)
- 常用参数:
-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m
2.12 其他
String.join():String.join(", ", "a", "b", "c")→"a, b, c"Files.lines()流式读取文件Comparator.comparing()链式排序ConcurrentHashMap改用 CAS + synchronized,性能大幅提升LongAdder、DoubleAdder— 比AtomicLong更高性能的累加器
三、Java 9(2017.09)
3.1 模块化系统(Project Jigsaw)
JDK 本身被拆分为多个模块,应用也可以定义自己的模块。
// module-info.java — 模块声明文件
module com.example.myapp {
requires java.sql; // 需要其他模块
requires java.logging;
exports com.example.api; // 对外暴露的包
opens com.example.dto; // 反射可访问
uses com.example.spi.Service; // 使用 SPI 服务
provides com.example.spi.Service with com.example.MyServiceImpl; // 提供服务实现
}常用 JDK 模块:java.base(默认依赖)、java.sql、java.xml、java.logging、java.desktop
3.2 JShell(交互式 REPL)
jshell> int x = 10;
jshell> x * 2;
$2 ==> 20
jshell> System.out.println("Hello JShell");
Hello JShell
jshell> /list # 列出所有输入
jshell> /vars # 列出所有变量
jshell> /methods # 列出所有方法
jshell> /exit3.3 集合工厂方法(不可变集合)
// 创建不可变集合(不能为 null,不能修改)
List<String> list = List.of("a", "b", "c");
Set<Integer> set = Set.of(1, 2, 3);
Map<String, Integer> map = Map.of("k1", 1, "k2", 2);
// 超过 10 个元素用重载版本
Map<String, Integer> large = Map.ofEntries(
Map.entry("k1", 1),
Map.entry("k2", 2),
Map.entry("k3", 3)
// ...
);
// 尝试修改会抛 UnsupportedOperationException
list.add("d"); // ❌3.4 接口私有方法
interface Greeting {
default void hello() {
say("Hello");
}
default void goodbye() {
say("Goodbye");
}
// 私有方法 — 提取默认方法中的公共代码
private void say(String msg) {
System.out.println(msg);
}
}3.5 Stream API 增强
// takeWhile — 一旦条件为 false 立即停止
Stream.of(1, 2, 3, 4, 5).takeWhile(n -> n < 4)
.forEach(System.out::print); // 123
// dropWhile — 条件为 true 时丢弃,第一次 false 后全保留
Stream.of(1, 2, 3, 4, 5).dropWhile(n -> n < 4)
.forEach(System.out::print); // 45
// iterate 增强 — 可带终止条件(旧版只能 limit)
Stream.iterate(1, n -> n <= 100, n -> n * 2)
.forEach(System.out::println); // 1, 2, 4, 8, 16, 32, 64
// ofNullable — 返回包含单元素或空的 Stream
Stream.ofNullable(null).count(); // 0
Stream.ofNullable("hello").count(); // 13.6 Optional 增强
// or() — 链式备选
Optional<String> result = first.or(() -> second).or(() -> third);
// ifPresentOrElse()
opt.ifPresentOrElse(
v -> System.out.println(v),
() -> System.out.println("缺省")
);
// stream() — 转为 Stream
opt.stream().forEach(System.out::println);3.7 响应式编程 Flow API
// java.util.concurrent.Flow 接口定义了发布-订阅模型
// 核心接口:Publisher、Subscriber、Subscription、Processor
// 更推荐使用 RxJava 或 Project Reactor,JDK 的 Flow 主要用于 JDK 内部3.8 G1 成为默认垃圾回收器
- 旧默认:Parallel GC
- 新默认:G1 GC(-XX:+UseG1GC)
3.9 其他
ProcessHandleAPI:获取和管理操作系统进程StackWalkingAPI:高效遍历调用栈- 多版本 JAR:一个 JAR 可为不同 Java 版本包含不同类实现
javax.xml.bind等模块标记为@Deprecated
四、Java 10(2018.03)
4.1 局部变量类型推断(var)
// var 只能用于局部变量 + 初始化
var list = new ArrayList<String>(); // ArrayList<String>
var path = Paths.get("/usr/bin"); // Path
var map = Map.of("k", "v"); // Map<String, String>
// forEach 中使用
for (var item : list) {
System.out.println(item);
}
// 不能用于:方法参数、返回类型、字段、没有初始化的声明
// var name; ❌
// public var method() {} ❌原则:var 只是语法糖,编译后类型不变;适合右侧能明确推断类型时使用;避免滥用导致可读性下降(如 var r = getSomething() 命名不清晰时)。
4.2 不可变集合增强(copyOf)
var list = List.of("a", "b", "c");
var copy = List.copyOf(list); // 不可变副本
// 如果原集合已不可变,直接返回原实例
var mutable = new ArrayList<String>();
var immutable = List.copyOf(mutable); // 安全副本4.3 Optional.orElseThrow()
// 等价于 get(),但语义更明确
String val = opt.orElseThrow(); // 无值抛 NoSuchElementException4.4 其他
- G1 并行 Full GC,减少停顿时间
- 应用程序类数据共享 (AppCDS)
- 基于时间的发布版本模型确立:每 6 个月一个新版本
五、Java 11(2018.09 LTS)
5.1 HTTP Client(标准化)
异步、支持 HTTP/2 和 WebSocket 的现代 HTTP 客户端。
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
// 同步 GET
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/data"))
.header("Accept", "application/json")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
// 异步 GET
CompletableFuture<HttpResponse<String>> future = client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
future.thenAccept(resp -> System.out.println(resp.body()));
// POST JSON
HttpRequest post = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/data"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("""
{"name": "test", "value": 123}
"""))
.build();5.2 String 新方法
// isBlank — 是否为空白(仅空白字符也返回 true)
" ".isBlank(); // true
// lines — 按行分割为 Stream
"line1\nline2\nline3".lines().count(); // 3
// strip / stripLeading / stripTrailing(Unicode 友好版 trim)
" hello ".strip(); // "hello"
// repeat — 重复 n 次
"abc".repeat(3); // "abcabcabc"5.3 Lambda 参数类型推断增强(var 用于 Lambda)
// Lambda 参数可以用 var(Java 11+)
list.stream()
.map((@NotNull var s) -> s.toLowerCase())
.collect(Collectors.toList());
// var 在 Lambda 中的意义:可以加注解5.4 集合 toArray 增强
List<String> list = List.of("a", "b", "c");
// 旧写法
String[] arr1 = list.toArray(new String[0]);
// Java 11+
String[] arr2 = list.toArray(String[]::new);5.5 Files 增强
// readString / writeString — 读写字符串(不再需要 Stream/Buffer)
String content = Files.readString(Path.of("test.txt"));
Files.writeString(Path.of("out.txt"), "Hello World");5.6 Flight Recorder
# 以前是商业功能,现在开源免费
java -XX:StartFlightRecording:filename=recording.jfr MyApp5.7 模块移除
移除了 java.xml.ws、java.xml.bind、java.activation、java.corba、java.transaction 等 Java EE 模块,使用时需额外引入依赖。
5.8 ZGC 实验性支持
可扩展的低延迟垃圾回收器,目标停顿时间 < 10ms。
六、Java 12(2019.03)
6.1 Switch 表达式(预览)
// 旧 switch(语句)
int numLetters;
switch (day) {
case MONDAY:
case FRIDAY:
numLetters = 6;
break;
default:
numLetters = 7;
}
// Java 12+ switch 表达式(预览)— 用 -> 语法
int numLetters = switch (day) {
case MONDAY, FRIDAY -> 6;
case TUESDAY -> 7;
default -> 8;
};6.2 Shenandoah GC 实验性支持
Red Hat 开发的低延迟 GC。
6.3 其他
- 改进 G1:可中止的混合收集
- 微基准测试套件(基于 JMH)
NumberFormat增加紧凑格式
七、Java 13(2019.09)
7.1 文本块(预览)
// 旧写法:丑陋的拼接
String json = "{\n" +
" \"name\": \"John\",\n" +
" \"age\": 30\n" +
"}";
// Java 13+ 文本块
String json = """
{
"name": "John",
"age": 30
}
""";7.2 Switch 表达式增强(预览)
使用 yield 关键字返回值(代替 break)。
int result = switch (x) {
case 1, 2 -> x * 10;
case 3 -> {
System.out.println("处理中...");
yield x * 100; // 返回复杂块的值
}
default -> 0;
};7.3 其他
- 重新实现旧版 Socket API
- ZGC:将未使用的堆内存归还给操作系统
- CDS 默认启用
八、Java 14(2020.03)
8.1 Switch 表达式(正式)
从预览转为正式特性。
int num = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case WEDNESDAY -> 9;
default -> {
int len = day.toString().length();
yield len;
}
};规则:
->后接单个表达式或{}块- 块中用
yield返回值(不是return) - 必须覆盖所有可能(default 或枚举全覆盖)
- 不允许 case 穿透(fall-through)
8.2 文本块(正式)
转为正式特性。在 Java 15 中最终敲定。
// 常用转义序列
String s = """
select * from user \
where id = 1 // \ 续行符,不产生换行
""";
// 结果:select * from user where id = 1
String s2 = """
hello \s
world // \s — 强制空格,防止末尾空格被 trim
""";8.3 instanceof 模式匹配(预览)
// 旧写法
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.length());
}
// Java 14+ 模式匹配
if (obj instanceof String s) {
System.out.println(s.length()); // 直接使用 s
}
// 复杂条件中也可用
if (obj instanceof String s && s.length() > 5) {
System.out.println(s);
}8.4 Record(预览)
不可变数据载体类,自动生成构造器、getter、equals、hashCode、toString。
record Point(int x, int y) {}
Point p = new Point(3, 5);
System.out.println(p.x()); // 3 — 访问器方法(无 get 前缀)
System.out.println(p.y()); // 5
System.out.println(p); // Point[x=3, y=5]
// Record 不能继承其他类(已继承 java.lang.Record)
// 所有字段都是 final
// 可以添加额外方法
record Rectangle(double width, double height) {
public double area() {
return width * height;
}
// 紧凑构造器(compact constructor)— 可做参数校验
public Rectangle {
if (width < 0 || height < 0) {
throw new IllegalArgumentException("不能为负数");
}
}
}8.5 NullPointerException 增强
JVM 会指出具体哪个变量为 null。
Exception in thread "main" java.lang.NullPointerException:
Cannot read field "name" because "user.address" is null8.6 其他
- CMS GC 被移除
- ZGC 在 macOS/Windows 上可用
- 外部内存访问 API(孵化)
九、Java 15(2020.09)
9.1 文本块正式敲定
从 Java 14 正式版经最终调整。
9.2 封闭类(Sealed Classes)预览
限制哪些类可以实现或继承。
// 只允许指定的类继承
public sealed class Shape
permits Circle, Rectangle, Triangle { }
final class Circle extends Shape { }
non-sealed class Rectangle extends Shape { } // non-sealed 开放给任意子类
final class Triangle extends Shape { }9.3 ZGC 正式版
- 从实验阶段转为正式特性
- 目标:亚毫秒级停顿,支持 TB 级堆大小
9.4 其他
- 隐藏类(Hidden Classes):运行时动态生成类,框架友好
- Nashorn JavaScript 引擎被移除
- Shenandoah GC 正式版
- EdDSA 签名算法的实现
十、Java 16(2021.03)
10.1 Record 正式版
从预览转为正式特性。
10.2 instanceof 模式匹配正式版
从预览转为正式特性。
10.3 Vector API(孵化器)
利用 CPU SIMD 指令进行矢量运算,提升数值计算性能。
// 孵化中,需要使用 --add-modules jdk.incubator.vector10.4 其他
- 外部链接器 API(孵化):替代 JNI
- 外部内存访问 API(孵化器二期)
- Unix 域套接字支持
- C++14 编写 HotSpot VM 代码
十一、Java 17(2021.09 LTS)
当前企业主流 LTS 版本,稳定且功能充足。
11.1 封闭类正式版
从预览转为正式特性。
sealed interface Expr
permits Constant, Add, Multiply { }
record Constant(int value) implements Expr { }
record Add(Expr left, Expr right) implements Expr { }
record Multiply(Expr left, Expr right) implements Expr { }
// 模式匹配的完备性检查——编译器确保 switch 覆盖所有情况(结合 Java 21 的模式匹配)11.2 伪随机数生成器增强
// 新接口:RandomGenerator
// 多种实现:L32X64MixRandom, L64X128StarStarRandom, Xoshiro256PlusPlus 等
RandomGenerator rng = RandomGenerator.of("L64X128MixRandom");
int n = rng.nextInt(100);11.3 macOS AArch64 支持
Apple M1/M2 (ARM 架构) 官方支持。
11.4 移除的安全管理器
SecurityManager 及相关类被标记为废弃,计划未来移除。
11.5 其他
- Applet API 被废弃
- RMI 激活被废弃
- 外部函数和内存 API(孵化二期)
十二、Java 18(2022.03)
12.1 默认字符集为 UTF-8
Charset.defaultCharset() 在所有平台的 JDK 内部默认返回 UTF-8,解决长期存在的跨平台乱码问题。
12.2 简单 Web 服务器
# 命令行启动,将当前目录作为静态资源目录,端口 8000
jwebserver
# 指定端口和目录
jwebserver -p 9000 -d /path/to/root
# Java API
var server = SimpleFileServer.createFileServer(
new InetSocketAddress(8080), Path.of("/var/www"), "/");
server.start();12.3 @snippet 标签
JavaDoc 中嵌入可测试的代码片段。
/**
* 计算两数之和。
* {@snippet :
* int result = MathUtils.add(1, 2); // @highlight substring="result"
* System.out.println(result); // 3
* }
*/
public static int add(int a, int b) { return a + b; }12.4 其他
- Vector API(孵化器三期)
- 外部函数和内存 API(孵化三期)
- 互联网地址解析 SPI
- G1 优化、ZGC 优化
十三、Java 19(2022.09)
13.1 虚拟线程(Virtual Threads)预览
协程/纤程实现,轻量级线程,大幅提升并发吞吐量。
// 创建虚拟线程——每个请求一个虚拟线程
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 100_000; i++) {
executor.submit(() -> {
// 处理业务(可包含阻塞 I/O)
Thread.sleep(1000); // 虚拟线程阻塞时释放底层 OS 线程
return "done";
});
}
}
// 单独创建
Thread vt = Thread.startVirtualThread(() -> {
System.out.println("运行在虚拟线程中");
});核心优势:
- 创建/切换代价极低,可以轻松运行数十万甚至百万个
- 当虚拟线程阻塞时,底层 OS 线程被释放去执行其他虚拟线程
- 不用改代码,
Thread.sleep()、synchronized、I/O 等都已适配
13.2 结构化并发(孵化器)
将多个并发子任务作为一个整体单元进行管理。
// 结构化并发(孵化中)
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> user = scope.fork(() -> findUser());
Future<Integer> order = scope.fork(() -> findOrder());
scope.join(); // 等所有 fork 完成或有一个失败
scope.throwIfFailed(); // 任一个失败就抛异常
return new Response(user.resultNow(), order.resultNow());
}
// scope 结束时自动取消所有未完成的子任务13.3 Record 模式匹配(预览)
record Point(int x, int y) {}
void print(Object obj) {
if (obj instanceof Point(int x, int y)) {
System.out.println("x=" + x + ", y=" + y);
}
}
// 嵌套类型也可以解构
record Line(Point start, Point end) {}
if (obj instanceof Line(Point(int x1, int y1), Point(int x2, int y2))) {
System.out.printf("从 (%d, %d) 到 (%d, %d)%n", x1, y1, x2, y2);
}13.4 switch 模式匹配(第三次预览)
String formatted = switch (obj) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
case null -> "null";
default -> obj.toString();
};13.5 其他
- 外部函数和内存 API(孵化四期)
- Vector API(孵化器四期)
十四、Java 20(2023.03)
14.1 虚拟线程(第二次预览)
- 性能优化、API 稳定化
- 修复了与 synchronized 交互时的 pinning 问题
14.2 作用域值(Scoped Values)孵化器
替代线程局部变量(ThreadLocal)的现代方案,在虚拟线程场景下更高效。
// 定义一个 ScopedValue
final static ScopedValue<String> USER = ScopedValue.newInstance();
ScopedValue.where(USER, "admin").run(() -> {
// 这里可以获取到 USER = "admin"
System.out.println(USER.get());
});
// 出作用域后不可访问14.3 Record 模式匹配(第二次预览)
- 类型参数推断增强
- 支持泛型 Record 的类型推断
14.4 其他
- switch 模式匹配(第四次预览)
- 外部函数和内存 API(孵化五期)
- 虚拟线程 + 结构化并发持续优化
十五、Java 21(2023.09 LTS)
当前最新 LTS 版本,生产就绪的重大更新。
15.1 虚拟线程正式版
从预览转为正式特性,Java 并发编程的里程碑。
// 方式一:虚拟线程执行器
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> task());
}
// 方式二:直接启动
Thread vt = Thread.ofVirtual().start(() -> task());
// 方式三:Thread.Builder
Thread vt = Thread.ofVirtual()
.name("my-virtual-thread")
.unstarted(() -> task());
vt.start();
vt.join();
// 虚拟线程与平台线程对比
// 平台线程(OS 线程):约 1MB 栈空间,重量级
// 虚拟线程:按需分配栈(堆上),可创建上百万个适用场景:高并发 I/O 密集型应用(Web 服务器、微服务、数据库代理等)
注意事项:
- 虚拟线程不支持
Thread.setPriority() - 不适合 CPU 密集计算(此时用平台线程 + ForkJoinPool)
- synchronized 块/方法中长时间阻塞可能 pin 底层线程(Java 21 已缓解,Java 24 完全解决)
15.2 Record 模式匹配正式版
// 嵌套解构
interface Expr { }
record Constant(int value) implements Expr { }
record Add(Expr left, Expr right) implements Expr { }
int eval(Expr expr) {
return switch (expr) {
case Constant(int val) -> val;
case Add(Expr left, Expr right) -> eval(left) + eval(right);
};
}15.3 switch 模式匹配正式版
sealed interface Shape permits Circle, Rectangle, Triangle { }
record Circle(double radius) implements Shape { }
record Rectangle(double width, double height) implements Shape { }
record Triangle(double base, double height) implements Shape { }
// 无 default ——编译器检查封闭类已全覆盖
double area(Shape shape) {
return switch (shape) {
case Circle(var r) -> Math.PI * r * r;
case Rectangle(var w, var h) -> w * h;
case Triangle(var b, var h) -> 0.5 * b * h;
};
}
// when 子句(守卫)
String describe(Shape shape) {
return switch (shape) {
case Circle(var r) when r > 100 -> "大圆";
case Circle(var r) -> "小圆";
case Rectangle(var w, var h) when w == h -> "正方形";
default -> "其他形状";
};
}15.4 字符串模板(预览)
// STR — 内置模板处理器
String name = "张三";
int age = 25;
String msg = STR."你好,我叫\{name},今年\{age}岁。";
// 结果:你好,我叫张三,今年25岁。
// 多行模板
String json = STR."""
{
"name": "\{name}",
"age": \{age}
}
""";
// FMT — 格式化模板
double price = 12.3456;
String formatted = FMT."价格:%.2f\{price}"; // 价格:12.35
// 自定义模板处理器 — RAW 返回原始模板
StringTemplate st = RAW."Hello \{name}";注意:字符串模板在 Java 21/22 为预览,Java 23 中因设计争议被回退重新设计。
15.5 有序集合接口(Sequenced Collections)
为集合框架定义了遇到顺序的清晰语义。
// 新增接口
// SequencedCollection<E> extends Collection<E>
// SequencedSet<E> extends SequencedCollection<E>, Set<E>
// SequencedMap<K, V> extends Map<K, V>
// List → SequencedCollection (ArrayList、LinkedList)
// SortedSet → SequencedSet (TreeSet)
// LinkedHashSet → SequencedSet
// SortedMap → SequencedMap (TreeMap)
// LinkedHashMap → SequencedMap
// 新增方法
list.addFirst(e);
list.addLast(e);
E first = list.getFirst();
E last = list.getLast();
E e = list.removeFirst();
e = list.removeLast();
// reversed() — 反转视图(不复制)
SequencedCollection<E> reversed = list.reversed();
// Map 同理
map.firstEntry();
map.lastEntry();
map.pollFirstEntry();
map.pollLastEntry();
sequencedMap.putFirst(k, v);
sequencedMap.putLast(k, v);
sequencedMap.reversed();15.6 分代 ZGC
ZGC 增加分代支持,年轻对象和老对象分别管理,吞吐量提高。
# 启用分代 ZGC
-XX:+UseZGC -XX:+ZGenerational15.7 密钥封装机制(KEM)
使用现代非对称加密进行密钥交换的标准 API。
KeyPairGenerator kpg = KeyPairGenerator.getInstance("X25519");
KeyPair keyPair = kpg.generateKeyPair();
KEM kem = KEM.getInstance("DHKEM");
// 发送方封装
KEM.Encapsulator enc = kem.newEncapsulator(keyPair.getPublic());
KEM.Encapsulated encResult = enc.encapsulate();
SecretKey sharedKey1 = encResult.key();
// 接收方解封装
KEM.Decapsulator dec = kem.newDecapsulator(keyPair.getPrivate());
SecretKey sharedKey2 = dec.decapsulate(encResult.encapsulation());
// sharedKey1.equals(sharedKey2) == true15.8 其他
- 外部函数和内存 API(孵化六期)
- Vector API(孵化器六期)
- 废弃
Thread.countStackFrames()等过时方法 - Windows 32-bit 版本停止构建
十六、Java 22(2024.03)
16.1 语句前的 super(...)(预览)
// 以前:子类构造器中 super() 或 this() 必须是第一条语句
class Sub extends Base {
Sub(Object arg) {
// 想校验参数后再调 super,以前做不到,只能写静态方法
super(arg); // 必须是第一条语句
}
}
// Java 22+:构造器第一条语句前可以写表达式语句
class Sub extends Base {
Sub(Object arg) {
Objects.requireNonNull(arg); // ← 可以在 super() 前校验
super(arg);
}
}16.2 隐式声明的类和实例 main
// 学生友好 — 不需要 public class + static void main 样板
void main() {
System.out.println("Hello World");
}
// 或者更简
void main() {
println("Hello World"); // java.io.IO 自动导入
}16.3 字符串模板(第二次预览)
- 模板处理器 API 优化
StringTemplate接口增强
16.4 流收集器增强(预览)
List<String> names = stringStream
.gather(Gatherers.fold(
() -> new ArrayList<String>(),
(list, s) -> { if (s.length() > 3) list.add(s); return list; }
))
.collect(Collectors.toList());16.5 外部函数和内存 API 正式版
从孵化转为正式特性,现代的 JNI 替代方案。
// 调用 C 标准库的 strlen
Linker linker = Linker.nativeLinker();
SymbolLookup lookup = SymbolLookup.loaderLookup();
MethodHandle strlen = linker.downcallHandle(
lookup.find("strlen").get(),
FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)
);
try (Arena arena = Arena.ofConfined()) {
MemorySegment str = arena.allocateFrom("Hello");
long len = (long) strlen.invoke(str);
System.out.println(len); // 5
}16.6 其他
- 构造器中的
this可以提前使用(预览) - 分代 ZGC 默认启用
- 多文件源程序启动:
java Main.java自动编译关联文件
十七、Java 23(2024.09)
17.1 模式匹配中的原始类型(预览)
// switch 中支持原始类型模式
String result = switch (x) {
case int i when i > 0 -> "正整数";
case int i when i < 0 -> "负整数";
case int i -> "零";
};
// instanceof 也可以
if (obj instanceof long l) {
System.out.println(l * 2);
}17.2 灵活的构造方法体(第二次预览)
super()前语句能力增强。
17.3 Markdown 文档注释
/// 计算两数之和。
///
/// # 示例
/// ```
/// int result = Calculator.add(3, 5);
/// ```
///
/// @param a 第一个加数
/// @param b 第二个加数
/// @return 两个数的和
public static int add(int a, int b) {
return a + b;
}17.4 其他
- 字符串模板被回退(移除预览),等待重新设计
- 隐式声明类和 main 方法(第二次预览)
- ZGC:默认分代模式
- 默认禁用
sun.misc.Unsafe的内存访问(用外部函数和内存 API 代替)
十八、Java 24(2023+ 展望)
持续演进中的版本,重点关注:
- 值类型(Value Types / Project Valhalla):将基本类型语义扩展到自定义类型,消除装箱开销,扁平化内存布局。
value class Point { private int x; private int y; } - 虚拟线程 pinning 问题彻底解决:synchronized 块不再导致虚拟线程 pin 底层线程
- 模式匹配持续增强
- 字符串模板重新设计
版本速查表
| 版本 | 发布时间 | LTS | 核心特性 |
|---|---|---|---|
| 7 | 2011.07 | switch-String、try-with-resources、菱形操作符、NIO.2 | |
| 8 | 2014.03 | ✓ | Lambda、Stream、Optional、新日期API、CompletableFuture |
| 9 | 2017.09 | 模块化、JShell、不可变集合工厂、接口私有方法 | |
| 10 | 2018.03 | var 局部变量类型推断 | |
| 11 | 2018.09 | ✓ | HTTP Client、String 增强、Flight Recorder |
| 12 | 2019.03 | Switch 表达式(预览)、Shenandoah GC | |
| 13 | 2019.09 | 文本块(预览)、Switch 表达式 yield | |
| 14 | 2020.03 | Switch 正式、Record 预览、instanceof 模式匹配 | |
| 15 | 2020.09 | 文本块正式、封闭类预览、ZGC 正式 | |
| 16 | 2021.03 | Record 正式、instanceof 模式匹配正式 | |
| 17 | 2021.09 | ✓ | 封闭类正式、PRNG 增强、移除 SecurityManager |
| 18 | 2022.03 | 默认 UTF-8、简易 Web 服务器、@snippet | |
| 19 | 2022.09 | 虚拟线程预览、结构化并发、Record 模式匹配 | |
| 20 | 2023.03 | 虚拟线程预览2、Scoped Values | |
| 21 | 2023.09 | ✓ | 虚拟线程正式、模式匹配正式、字符串模板、分代ZGC |
| 22 | 2024.03 | super()前语句、外部函数和内存 API 正式 | |
| 23 | 2024.09 | 原始类型模式、Markdown 文档注释 | |
| 24 | 2025.03 | 值类型(Valhalla)、虚拟线程 pinning 修复 |
升级建议
- 从 Java 8 升级 → 直接跳 Java 17 或 Java 21,虚拟线程和模式匹配是生产级特性
- 从 Java 11 升级 → Java 21 LTS,获得虚拟线程、Record、封闭类等全套现代特性
- 从 Java 17 升级 → 如需虚拟线程和高并发能力就升 Java 21
- 新项目 → 直接 Java 21 LTS 起步,2025 年可关注 Java 24/25 动态
模块化迁移:从 8 → 9+ 遇到 java.xml.bind 等找不到类时,添加对应 Maven/Gradle 依赖即可。
