Skip to content
<

Java 14 将 Switc⁢h 表达式正式化,并⁡引入了 Record⁡s、instanceof 模式匹配作为预览特性。

正式特性

【必备】Switch 表达式

Java 14 将 Swit⁢ch 表达式转正了⁡,让条件判断变得更简洁⁡和安全。

在这之前,传统的 switc⁢h 语句存在不少问⁡题,比如需要手动添⁡加 break 防止穿透、赋值不方便等:

java
String dayType;  
switch (day) {  
    case MONDAY:  
    case TUESDAY:  
    case WEDNESDAY:  
    case THURSDAY:  
    case FRIDAY:  
        dayType = "工作日";  
        break;  
    case SATURDAY:  
    case SUNDAY:  
        dayType = "周末";  
        break;  
    default:  
        dayType = "未知";  
        break;  
}  
  
// 赋值不方便  
int score;  
switch (grade) {  
    case 'A':  
        System.out.println("优秀!");  
        score = 90;  
        break;  
    case 'B':  
        score = 80;  
        break;  
    default:  
        score = 0;  
}

在 Java 14 之后,可以直接这么写:

java
// Java 14 的简洁写法  
String dayType = switch (day) {  
    case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "工作日";  
    case SATURDAY, SUNDAY -> "周末";  
    default -> "未知";  
};  
  
// 支持复杂逻辑的 yield 关键字  
int score = switch (grade) {  
    case 'A' -> {  
        System.out.println("优秀!");  
        yield 90;  // 使用 yield 返回值  
    }  
    case 'B' -> 80;  
    default -> 0;  
};

上述代码中,我们使用了 Sw⁢itch 表达式增⁡强的几个特性:

  • 箭头语法:使用 -> 替代冒号,自动防止 fall-through(不用写 break 了)

  • 多标签支持:case A, B, C -> 一行处理多个条件

  • 表达式求值:可以直接使用 yield 关键字返回值并赋给变量

这样一来,多条件判断变得更优⁢雅了!还能避免忘记⁡ break 导致的逻⁡辑错误。

java
// 实际应用示例:根据月份判断季节  
String season = switch (month) {  
    case 12, 1, 2 -> "冬季";  
    case 3, 4, 5 -> "春季";   
    case 6, 7, 8 -> "夏季";  
    case 9, 10, 11 -> "秋季";  
    default -> throw new IllegalArgumentException("无效月份: " + month);  
};

【必备】有用的空指针异常

Java 14 改进了 NullPointerException⁢ 的错误信息。JVM 会提供更详细的堆栈跟⁡踪信息,指出导致异常的具体位置和原因,让调⁡试变得更加容易

传统的 NPE 信息往往只告⁢诉你在哪一行出错,⁡但不知道具体是哪个⁡变量为 null:

java
// 传统的 NPE 信息  
Exception in thread "main" java.lang.NullPointerException  
    at MyClass.method(MyClass.java:15)

Java 14 的改进版本会提供更详细的信息:

java
// Java 14 的详细 NPE 信息  
Exception in thread "main" java.lang.NullPointerException:   
    Cannot invoke "String.length()" because "user.getName()" is null  
    at MyClass.method(MyClass.java:15)

这个特性需要通过 JVM 参数启用:

bash
java -XX:+ShowCodeDetailsInExceptionMessages MyApp

【了解】G1 垃圾收集器改进

G1 的 NUMA 感知内存分配

Java 14 改进了 G1 垃圾⁢收集器,使其能够感知 ⁡NUMA(Non-Un⁡iform Memory Access)架构:

bash
java -XX:+UseG1GC -XX:+UseNUMA MyApp

这个改进可以:

  • 提高多 CPU 系统的内存访问效率

  • 减少跨 NUMA 节点的内存访问

  • 改善大型服务器的性能表现

macOS 和 Windows 上的 ZGC

Java 14 将 ZGC ⁢扩展到 macOS⁡ 和 Window⁡s 平台:

bash
# macOS 上启用 ZGC  
java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC MyApp  
  
# Windows 上启用 ZGC    
java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC MyApp

之前 ZGC 只支持 Lin⁢ux,现在跨平台支⁡持让更多开发者可以⁡体验低延迟 GC。

【了解】JFR 事件流

Java 14 引入了 JFR⁢(Java Flig⁡ht Recorde⁡r)事件流 API,允许实时消费 JFR 事件:

java
import jdk.jfr.consumer.RecordingStream;  
  
public class JFRStreamExample {  
    public static void main(String[] args) {  
        try (RecordingStream rs = new RecordingStream()) {  
            // 启用 GC 事件  
            rs.enable("jdk.GarbageCollection");  
              
            // 设置事件处理器  
            rs.onEvent("jdk.GarbageCollection", event -> {  
                System.out.println("GC 事件: " + event.getValue("gcId"));  
                System.out.println("GC 时间: " + event.getDuration());  
            });  
              
            // 启用 CPU 负载事件  
            rs.enable("jdk.CPULoad").withPeriod(Duration.ofSeconds(1));  
            rs.onEvent("jdk.CPULoad", event -> {  
                double cpuLoad = event.getFloat("machineTotal");  
                System.out.println("CPU 负载: " + cpuLoad * 100 + "%");  
            });  
              
            // 开始流式处理  
            rs.start();  
        }  
    }  
}

这个 API 可以用于:

  • 实时性能监控

  • 自动化性能分析

  • 构建自定义监控工具

【了解】其他正式特性

非易失性映射字节缓冲区

Java 14 支持将 Ma⁢ppedByteB⁡uffer 映射到⁡非易失性内存(NVM):

java
import java.nio.MappedByteBuffer;  
import java.nio.channels.FileChannel;  
import java.nio.file.StandardOpenOption;  
  
// 映射到非易失性内存  
try (FileChannel channel = FileChannel.open(  
        Paths.get("/mnt/pmem/datafile"),   
        StandardOpenOption.READ,   
        StandardOpenOption.WRITE)) {  
      
    MappedByteBuffer buffer = channel.map(  
        FileChannel.MapMode.READ_WRITE, 0, channel.size());  
      
    // 数据直接持久化到 NVM  
    buffer.putInt(42);  
    buffer.force(); // 强制写入  
}

删除 CMS 垃圾收集器

Java 14 正式移除了 ⁢CMS(Concu⁡rrent Mar⁡k Sweep)垃圾收集器:

bash
# 这个参数在 Java 14 中不再有效  
# java -XX:+UseConcMarkSweepGC MyApp  // 已移除  
  
# 推荐使用 G1 或 ZGC  
java -XX:+UseG1GC MyApp

删除 Pack200 工具和 API

Java 14 移除了 Pa⁢ck200 压缩工⁡具和相关 API:

java
// 这些 API 在 Java 14 中已被移除  
// Pack200.Packer packer = Pack200.newPacker();  
// Pack200.Unpacker unpacker = Pack200.newUnpacker();

预览特性

【了解】Records(预览)

Records 是 Java⁢ 14 引入的预览⁡特性,用于创建不可⁡变的数据载体类:

java
// 启用预览特性  
// javac --enable-preview --release 14 RecordExample.java  
// java --enable-preview RecordExample  
  
// 定义一个简单的 Record  
public record Person(String name, int age) {}  
  
// 编译器自动生成:  
// - 构造函数  
// - getter 方法(name(), age())  
// - equals() 和 hashCode()  
// - toString()

使用 Records:

java
public class RecordExample {  
    public static void main(String[] args) {  
        Person person = new Person("张三", 25);  
          
        System.out.println(person.name());      // 张三  
        System.out.println(person.age());       // 25  
        System.out.println(person.toString());  // Person[name=张三, age=25]  
          
        // Records 是不可变的  
        Person another = new Person("张三", 25);  
        System.out.println(person.equals(another)); // true  
    }  
}

Records 还支持自定义方法和验证:

java
public record BankAccount(String accountNumber, double balance) {  
    // 紧凑构造函数 - 用于验证  
    public BankAccount {  
        if (balance < 0) {  
            throw new IllegalArgumentException("余额不能为负数");  
        }  
        if (accountNumber == null || accountNumber.isBlank()) {  
            throw new IllegalArgumentException("账号不能为空");  
        }  
    }  
      
    // 自定义方法  
    public boolean isVIP() {  
        return balance > 100000;  
    }  
      
    // 静态工厂方法  
    public static BankAccount createSavingsAccount(String accountNumber) {  
        return new BankAccount(accountNumber, 0.0);  
    }  
}

【了解】instanceof 的模式匹配(预览)

Java 14 引入了 instan⁢ceof 的模式匹配作为⁡预览特性:       ⁡

java
// 传统写法  
Object obj = "Hello World";  
if (obj instanceof String) {  
    String str = (String) obj;  
    System.out.println("字符串长度: " + str.length());  
}  
  
// Java 14 模式匹配(预览)  
if (obj instanceof String str) {  
    System.out.println("字符串长度: " + str.length());  
}

模式匹配的变量作用域:

java
public void processObject(Object obj) {  
    if (obj instanceof String str && str.length() > 5) {  
        System.out.println("长字符串: " + str);  
        // str 在这里可用  
    }  
    // str 在这里不可用  
      
    if (!(obj instanceof String str)) {  
        return;  
    }  
    // 由于前面的条件,这里 str 是可用的  
    System.out.println("字符串: " + str);  
}

【了解】文本块(第二次预览)

Java 14 继续完善文本块特性,添加了两个转义序列:

java
// \s - 表示空格  
String text1 = """  
               Hello\sWorld  
               """;  
// 结果: "Hello World\n"  
  
// \ - 行末转义,避免换行  
String text2 = """  
               This is a very long line that \  
               continues on the next line  
               """;  
// 结果: "This is a very long line that continues on the next line\n"

孵化器特性         ⁢         ⁡         ⁡

【了解】打包工具(孵化器)

Java 14 引入了 jp⁢ackage 工具⁡作为孵化器特性,可⁡以将 Java 应用打包成平台特定的安装包:

bash
# 创建可执行文件  
jpackage --input target/ \  
         --name MyApp \  
         --main-jar myapp.jar \  
         --main-class com.example.Main  
  
# 创建 Windows 安装包  
jpackage --input target/ \  
         --name MyApp \  
         --main-jar myapp.jar \  
         --main-class com.example.Main \  
         --type msi  
  
# 创建 macOS 安装包  
jpackage --input target/ \  
         --name MyApp \  
         --main-jar myapp.jar \  
         --main-class com.example.Main \  
         --type dmg

【了解】外部内存访问 API(孵化器)

Java 14 引入了外部内⁢存访问 API,提⁡供安全高效的堆外内⁡存操作:

java
import jdk.incubator.foreign.*;  
  
// 分配堆外内存  
try (MemorySegment segment = MemorySegment.allocateNative(1024)) {  
    MemoryAddress address = segment.baseAddress();  
      
    // 写入数据  
    MemoryAccess.setIntAtOffset(segment, 0, 42);  
    MemoryAccess.setIntAtOffset(segment, 4, 24);  
      
    // 读取数据  
    int value1 = MemoryAccess.getIntAtOffset(segment, 0);  
    int value2 = MemoryAccess.getIntAtOffset(segment, 4);  
      
    System.out.println("值1: " + value1 + ", 值2: " + value2);  
}  
// 内存自动释放

总结

Java 14 是一个重要的版本,Switch 表达式的正式⁢化让条件判断更加优雅,改进的 NPE 信⁡息让调试更加容易。Records 和 i⁡nstanceof 模式匹配虽然还是预览特性,但已经显示出巨大的潜力。

GC 方面的改进,特别是 ZGC 的跨平台⁢支持和 G1 的 NUMA ⁡感知,为高性能应用提供了更⁡多选择。JFR 事件流 API 则为实时监控开辟了新的可能性。Ea7H6DxcZeWlVJFFEnFyn3Lx21/mLUEMxr9P/hnm5xs=

虽然 Java 14 不是 LTS 版本⁢,但它为后续版本奠定了重要⁡基础,特别是 Record⁡s 和模式匹配等特性在后续版本中得到了进一步完善。