Java 12~14 新特性
Java新特征系列
- Java 9~11 新特性
- 一、Java 12 新特性
- 1.1、Switch 表达式(预览)
- 1.2、字符串增强
- 1.3、紧凑数字格式化
- 1.4、文件内容比对
- 1.5、Teeing Collector
- 1.6、JVM 改进
- 1.7、其他
- 二、Java 13 新特性
- 2.1、文本块(Text Blocks,预览特性)
- 2.2、Switch 表达式增强(预览特性)
- 2.3、动态应用程序类-数据共享(Dynamic CDS)
- 2.4、Socket API重构
- 2.5、ZGC 增强
- 2.6、文件系统新增方法
- 2.7、隐藏类(Hidden Classes) (预览)
- 2.8、Unicode 12.1 支持
- 三、Java 14 新特性
- 3.1、Switch 表达式(正式版)
- 3.2、Records(预览特性)
- 3.3、文本块改进(第二预览)
- 3.4、instanceof 模式匹配(预览特性)
- 3.5、空指针异常信息增强
- 3.6、G1 的 NUMA 可识别内存分配
- 3.7、ZGC 支持 macOS 和 Windows
- 3.8、删除 CMS 垃圾回收器
- 3.9、其他特性
- 总结
Java 12 至 14 通过引入 Switch 表达式、文本块、Records(数据类)、模式匹配 instanceof 等简化代码结构,优化 ZGC/G1 垃圾回收性能,增强空指针异常信息,并支持跨平台工具(如 jpackage),显著提升了开发效率、运行时性能及调试体验,同时为未来版本奠定新特性基础。
一、Java 12 新特性
官网:http://openjdk.java.net/projects/jdk/12/
1.1、Switch 表达式(预览)
简洁语法支持箭头 -> 和直接返回值:
public class SwitchDemo {
public static void main(String[] args) {
int day = 3;
String dayType = switch (day) {
case 1, 2, 3, 4, 5 -> "工作日";
case 6, 7 -> "周末";
default -> throw new IllegalArgumentException("无效的日期: " + day);
};
System.out.println(dayType); // 输出: 工作日
}
}
注意:需添加
--enable-preview
启用预览功能。
编译运行
javac --enable-preview --release 12 SwitchDemo.java
java --enable-preview SwitchDemo
1.2、字符串增强
新增 indent() 和 transform() 方法:
indent(int n)
: 调整字符串缩进。transform(Function f)
: 对字符串应用函数。
public class StringDemo {
public static void main(String[] args) {
String text = "Hello\nJava\n12";
// 缩进每行 2 个空格
System.out.println(text.indent(2));
// 转换为大写
String upper = text.transform(String::toUpperCase);
System.out.println(upper);
}
}
1.3、紧凑数字格式化
用简短形式表示大数字:使用 NumberFormat
格式化紧凑数字(如 “1K” 代替 “1000”)。
import java.text.NumberFormat;
import java.util.Locale;
public class CompactFormatDemo {
public static void main(String[] args) {
NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
System.out.println(fmt.format(1000)); // 1K
System.out.println(fmt.format(1_000_000)); // 1M
}
}
1.4、文件内容比对
Files.mismatch() 查找两个文件的首个差异位置:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class FileMismatchDemo {
public static void main(String[] args) throws IOException {
Path file1 = Files.createTempFile("file1", ".txt");
Path file2 = Files.createTempFile("file2", ".txt");
Files.writeString(file1, "Java 12");
Files.writeString(file2, "Java 12!");
long mismatch = Files.mismatch(file1, file2);
System.out.println(mismatch); // 输出: 7(在第7个字符处不匹配)
}
}
1.5、Teeing Collector
Stream API
新增 teeing()
,支持同时进行两种收集操作并合并结果。
合并两个收集器的结果:
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class TeeingCollectorDemo {
public static void main(String[] args) {
double avg = Stream.of(10, 20, 30)
.collect(Collectors.teeing(
Collectors.summingDouble(Integer::intValue),
Collectors.counting(),
(sum, count) -> sum / count
));
System.out.println(avg); // 输出: 20.0
}
}
1.6、JVM 改进
●Shenandoah GC:低停顿垃圾收集器(需启用 -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC)
● 默认类数据共享(CDS):加速 JVM 启动
● 微基准测试套件:新增 JVM 性能测试工具
● G1的可中断 mixed GC:将Mixed GC集拆分为强制部分和可选部分,使G1垃圾收集器更有效地中止垃圾收集过程。
● G1归还不使用的内存:改进G1垃圾收集器,以便在不活动时将Java堆内存归还给操作系统。
1.7、其他
- JVM 常量 API:提供对类文件常量的符号描述(如
ClassDesc
)。 - 移除 ARM 32 位支持:仅保留 AArch64 实现。
Java 12 主要优化了代码简洁性(如 switch
表达式)、文件操作和数字格式化,同时改进了垃圾收集器性能。需注意预览特性需通过 --enable-preview
启用。
二、Java 13 新特性
官网:https://openjdk.org/projects/jdk/13/
2.1、文本块(Text Blocks,预览特性)
简化多行字符串的编写,使用 “”" 定义,自动处理缩进和换行。
目标:简化多行字符串(如JSON/XML/SQL)的编写,避免转义符混乱。
特性:
- 自动处理缩进(首行对齐左边界)
- 支持格式化插值(formatted()方法)
- 转义符简化(如"""内部双引号无需转义)
// 需启用预览参数:javac --release 13 --enable-preview ...
// 旧版写法(Java 13前)
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, Java 13</p>\n" +
" </body>\n" +
"</html>";
// Java 13文本块
String htmlBlock = """
<html>
<body>
<p>Hello, Java 13</p>
</body>
</html>
""";
2.2、Switch 表达式增强(预览特性)
使用 yield 返回值,支持更复杂的逻辑分支。
目标:将switch从语句升级为表达式,支持直接返回值和代码块。
优势:
- 箭头语法 -> 替代break
- yield关键字在代码块中显式返回值
- 支持多条件合并(逗号分隔)
int day = 3;
String dayType = switch (day) {
case 1, 2, 3, 4, 5 -> "Weekday";
case 6, 7 -> {
System.out.println("Weekend!");
yield "Weekend"; // 使用 yield 返回值
}
default -> throw new IllegalArgumentException("Invalid day: " + day);
};
System.out.println(dayType);
2.3、动态应用程序类-数据共享(Dynamic CDS)
优化启动时间,通过存档类减少重复加载。
场景:适用于微服务频繁重启环境,减少类加载时间(实测启动速度提升约10-20%)。
# 创建类存档
java -XX:ArchiveClassesAtExit=app.jsa -jar app.jar
# 使用存档运行
java -XX:SharedArchiveFile=app.jsa -jar app.jar
2.4、Socket API重构
替换旧的 java.net.Socket 实现,提升稳定性和性能,代码无需修改即可受益。
目标:用NioSocketImpl替代遗留的PlainSocketImpl实现,提升稳定性和性能。
改进:
- 基于NIO实现,减少同步锁竞争
- 支持java.lang.ref.Cleaner机制自动关闭Socket
- 旧实现可通过参数回退:-Djdk.net.usePlainSocketImpl=true
// 代码无变化,但底层实现优化
try (ServerSocket serverSocket = new ServerSocket(8080)) {
Socket clientSocket = serverSocket.accept();
// 处理请求...
}
2.5、ZGC 增强
支持将未使用内存返回给操作系统。
目标:ZGC垃圾回收器自动归还未使用的堆内存给操作系统。
效果:
- 空闲时自动收缩堆至-Xms设置的最小值
- 适合容器化环境(如Kubernetes),避免内存浪费
java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:ZUncommitDelay=300 ...
2.6、文件系统新增方法
FileSystems.newFileSystem 简化文件系统操作。
Path path = Path.of("file.zip");
FileSystem fs = FileSystems.newFileSystem(path);
// 操作 ZIP 文件系统
2.7、隐藏类(Hidden Classes) (预览)
动态生成不可发现的类,专为框架设计:
import java.lang.invoke.MethodHandles;
// 动态创建隐藏类(伪代码)
MethodHandles.Lookup lookup = MethodHandles.lookup();
byte[] bytecode = generateBytecode(); // 动态生成字节码
Class<?> hiddenClass = lookup.defineHiddenClass(bytecode, true).lookupClass();
适用于动态代理(如 Lambda 表达式实现)。
2.8、Unicode 12.1 支持
新增字符和表情符号:
System.out.println("\uD83E\uDD73"); // 输出 "🤳"(自拍表情)
Java 13 主要优化了开发体验(文本块、Switch 表达式)和性能(ZGC、动态 CDS),同时增强了底层 API(Socket、文件系统)。开发者可优先尝试文本块和 Switch 表达式提升代码可读性,框架作者可关注隐藏类的动态生成能力。
三、Java 14 新特性
官网:http://openjdk.java.net/projects/jdk/14/
3.1、Switch 表达式(正式版)
Java 14 将 Switch 表达式从预览特性转为正式特性,支持箭头语法和 yield
返回值。
String day = "MON";
String day2 = "WED";
System.out.println(calculateLetters(day)); // 输出:1
System.out.println(calculateLetters(day2));// 输出:3
private static int calculateLetters(String day) {
return switch (day) {
case "MON", "FRI" -> 1;
case "TUES" -> 2;
default -> day.length();
};
}
使用 switch 表达式来替换之前的 switch 语句,确实精简了不少代码,提高了编码效率,同时也可以规避一些可能由于不太经意而出现的意想不到的情况,可见 Java 在提高使用者编码效率、编码体验和简化使用方面一直在不停的努力中,同时也期待未来有更多的类似 lambda、switch 表达式这样的新特性出来。
3.2、Records(预览特性)
简化数据载体类的定义,自动生成 equals()
、hashCode()
和 toString()
方法。
// 传统 POJO 类
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 手动生成 getter/equals/hashCode/toString...
}
// Java 14 Records
public record Person(String name, int age) {}
// 使用示例
Person p = new Person("Alice", 30);
System.out.println(p.name()); // 输出: Alice
System.out.println(p); // 输出: Person[name=Alice, age=30]
注意:需添加
--enable-preview
启用预览功能。在Java17中标准版上线。
3.3、文本块改进(第二预览)
优化三引号 """
的空白处理,新增转义符 \s
和 \<line-terminator>
。
\
: 表示行尾,不引入换行符\s
:表示单个空格
// 第一预览版(Java 13)
String html = """
<html>
<body>
<p>Hello Java</p>
</body>
</html>
""";
// Java 14 新增转义符
String code = """
public void print() {
System.out.println("Hello\sWorld"); // \s 保留末尾空格
}
""";
System.out.println(code);
3.4、instanceof 模式匹配(预览特性)
简化类型检查和类型转换操作。
// 传统写法
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.length());
}
// Java 14 模式匹配
if (obj instanceof String s) { // 直接绑定变量 s
System.out.println(s.length());
}
3.5、空指针异常信息增强
明确提示空指针异常的具体位置。
String str = null;
try {
System.out.println(str.length());
} catch (NullPointerException e) {
e.printStackTrace();
}
// 输出示例:
// Cannot invoke "String.length()" because "str" is null
3.6、G1 的 NUMA 可识别内存分配
Java 14 改进非一致性内存访问(NUMA)系统上的 G1 垃圾收集器的整体性能,主要是对年轻代的内存分配进行优化,从而提高 CPU 计算过程中内存访问速度。
NUMA 是 non-unified memory access 的缩写,主要是指在当前的多插槽物理计算机体系中,比较普遍是多核的处理器,并且越来越多的具有 NUMA 内存访问体系结构,即内存与每个插槽或内核之间的距离并不相等。同时套接字之间的内存访问具有不同的性能特征,对更远的套接字的访问通常具有更多的时间消耗。这样每个核对于每一块或者某一区域的内存访问速度会随着核和物理内存所在的位置的远近而有不同的时延差异。
具体启用方式可以在 JVM 参数后面加上如下参数:
-XX:+UseNUMA
通过这种方式来启用可识别的内存分配方式,能够提高一些大型计算机的 G1 内存分配回收性能。
3.7、ZGC 支持 macOS 和 Windows
ZGC 垃圾收集器扩展至 macOS 和 Windows 平台。
# 在 macOS/Windows 上启用 ZGC
java -XX:+UseZGC -Xmx4G MyApp
3.8、删除 CMS 垃圾回收器
CMS 是老年代垃圾回收算法,通过标记-清除的方式进行内存回收,在内存回收过程中能够与用户线程并行执行。CMS 回收器可以与 Serial 回收器和 Parallel New 回收器搭配使用,CMS 主要通过并发的方式,适当减少系统的吞吐量以达到追求响应速度的目的,比较适合在追求 GC 速度的服务器上使用。
因为 CMS 回收算法在进行 GC 回收内存过程中是使用并行方式进行的,如果服务器 CPU 核数不多的情况下,进行 CMS 垃圾回收有可能造成比较高的负载。同时在 CMS 并行标记和并行清理时,应用线程还在继续运行,程序在运行过程中自然会创建新对象、释放不用对象,所以在这个过程中,会有新的不可达内存地址产生,而这部分的不可达内存是出现在标记过程结束之后,本轮 CMS 回收无法在周期内将它们回收掉,只能留在下次垃圾回收周期再清理掉。这样的垃圾就叫做浮动垃圾。由于垃圾收集和用户线程是并发执行的,因此 CMS 回收器不能像其他回收器那样进行内存回收,需要预留一些空间用来保存用户新创建的对象。由于 CMS 回收器在老年代中使用标记-清除的内存回收策略,势必会产生内存碎片,内存当碎片过多时,将会给大对象分配带来麻烦,往往会出现老年代还有空间但不能再保存对象的情况。
所以,早在几年前的 Java 9 中,就已经决定放弃使用 CMS 回收器了,而这次在 Java 14 中,是继之前 Java 9 中放弃使用 CMS 之后,彻底将其禁用,并删除与 CMS 有关的选项,同时清除与 CMS 有关的文档内容,至此曾经辉煌一度的 CMS 回收器,也将成为历史。
当在 Java 14 版本中,通过使用参数: -XX:+UseConcMarkSweepGC
,尝试使用 CMS 时,将会收到下面信息:
Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option UseConcMarkSweepGC; \
support was removed in <version>
3.9、其他特性
- JFR 事件流:通过 API 实时访问 JFR 数据。
- 打包工具 jpackage(孵化器):生成原生安装包,支持不同平台格式。
- **删除 pack200 和 unpack200 工具:**删除 pack200 和 unpack200 工具,以及 java.util.jar 包中的 Pack200 API。
- **弃用 ParallelScavenge 和 SerialOld GC 的组合使用:**由于这两 GC 算法组合很少使用,却要花费巨大工作量来进行维护,所以在 Java 14 版本中,考虑将这两 GC 的组合弃用。
总结
Java 14 的核心改进方向:
- 开发效率:Switch 表达式、文本块、记录类减少样板代码。
- 性能优化:ZGC 跨平台支持、NUMA 感知提升吞吐量。
- 调试增强:NullPointerException 精准定位问题来源。
- 未来特性铺垫:模式匹配和记录类为后续版本(如 Java 15+)的正式化奠定基础。
开发者可优先尝试 Switch 表达式和文本块,框架开发者可探索记录类和模式匹配的潜力。