Java21-新特性

  1. 概述
    在本文中,我们将讨论Java21中添加的新特性和增强功能。
    Java21于2023年9月19日发布,是继之前的Java17之后的最新LTS版本。

  2. JEP清单

接下来,我们将讨论最显著的增强,也称为Java增强建议(JEP),这是引入的语言的新版本。

2.1 记录模式(JEP 440)

记录模式作为预览功能包含在Java19和Java20中。现在,Java21,它们超出预览功能,并包括一些改进。

这个JEP扩展了现有的模式匹配特性来解构记录类实例,从而能够编写复杂的数据查询。此外,这个JEP增加了对嵌套模式的支持,以实现更可组合的数据查询。

例如,我们可以更简洁地编写代码:

record Point(int x, int y) {}
    
public static int beforeRecordPattern(Object obj) {
    int sum = 0;
    if(obj instanceof Point p) {
        int x = p.x();
        int y = p.y();
        sum = x+y;
    }
    return sum;
}
    
public static int afterRecordPattern(Object obj) {
    if(obj instanceof Point(int x, int y)) {
        return x+y;
    }
    return 0;
}

因此,我们还可以将记录嵌套在记录中并解构它们:

enum Color {RED, GREEN, BLUE}
record ColoredPoint(Point point, Color color) {}
 
record RandomPoint(ColoredPoint cp) {}
public static Color getRamdomPointColor(RandomPoint r) {
    if(r instanceof RandomPoint(ColoredPoint cp)) {
        return cp.color();
    }
    return null;
}

上面,我们直接从ColoredPoint访问. color()方法。

2.2.开关(JEP 441)的模式匹配

最初在JDK 17中引入,开关的模式匹配在JDK 18、19和20中得到改进,并在JDK 21中进一步改进。

此特性的主要目标是允许switch case标签中的模式,并提高switch语句和表达式的表达能力。此外,还通过允许空大小写标签来处理NullPointerException。
让我们通过一个例子来探索这一点。假设我们有一个Account类:

static class Account{
    double getBalance(){
       return 0;
    }
}

我们将其扩展到各种类型的账户,每种账户都有其计算余额的方法:

static class SavingsAccount extends Account {
    double getSavings() {
        return 100;
    }
}
static class TermAccount extends Account {
    double getTermAccount() {
        return 1000;
    } 
}
static class CurrentAccount extends Account {
    double getCurrentAccount() {
        return 10000;
    } 
}

在Java21之前,我们可以使用下面的代码来获取余额:

static double getBalanceWithOutSwitchPattern(Account account) {
    double balance = 0;
    if(account instanceof SavingsAccount sa) {
        balance = sa.getSavings();
    }
    else if(account instanceof TermAccount ta) {
        balance = ta.getTermAccount();
    }
    else if(account instanceof CurrentAccount ca) {
        balance = ca.getCurrentAccount();
    }
    return balance;
}

上面的代码不是很有表现力,因为我们在if-else情况下有很多噪音。使用Java21,我们可以利用case标签中的模式来更简洁地编写相同的逻辑:

static double getBalanceWithSwitchPattern(Account account) {
    double result = 0;
    switch (account) {
        case null -> throw new RuntimeException("Oops, account is null");
        case SavingsAccount sa -> result = sa.getSavings();
        case TermAccount ta -> result = ta.getTermAccount();
        case CurrentAccount ca -> result = ca.getCurrentAccount();
        default -> result = account.getBalance();
    };
    return result;
}

为了确认我们写的是正确的,让我们用一个测试来证明这一点:

SwitchPattern.SavingsAccount sa = new SwitchPattern.SavingsAccount();
SwitchPattern.TermAccount ta = new SwitchPattern.TermAccount();
SwitchPattern.CurrentAccount ca = new SwitchPattern.CurrentAccount();

assertEquals(SwitchPattern.getBalanceWithOutSwitchPattern(sa), SwitchPattern.getBalanceWithSwitchPattern(sa));
assertEquals(SwitchPattern.getBalanceWithOutSwitchPattern(ta), SwitchPattern.getBalanceWithSwitchPattern(ta));
assertEquals(SwitchPattern.getBalanceWithOutSwitchPattern(ca), SwitchPattern.getBalanceWithSwitchPattern(ca));

所以,我们只是更简洁地重写了一个开关。

模式case标签还支持与同一标签的表达式匹配。例如,假设我们需要处理一个包含简单“Yes”或“No”的输入字符串:

static String processInputOld(String input) {
    String output = null;
    switch(input) {
        case null -> output = "Oops, null";
        case String s -> {
            if("Yes".equalsIgnoreCase(s)) {
                output = "It's Yes";
            }
            else if("No".equalsIgnoreCase(s)) {
                output = "It's No";
            }
            else {
                output = "Try Again";
            }
        }
    }
    return output;
}

同样,我们可以看到编写if-else逻辑会变得丑。相反,在Java21中,我们可以使用当子句以及case标签来匹配标签的值与表达式:

static String processInputNew(String input) {
    String output = null;
    switch(input) {
        case null -> output = "Oops, null";
        case String s when "Yes".equalsIgnoreCase(s) -> output = "It's Yes";
        case String s when "No".equalsIgnoreCase(s) -> output = "It's No";
        case String s -> output = "Try Again";
    }
    return output;
} 

2.3. 2.3.字符串文字(JEP 430)

Java提供了几种使用字符串文字和表达式组合字符串的机制。其中一些是字符串连接、StringBuilder类、String类format()方法和MessageFormat类。
Java21引入了字符串模板。这些通过将文字文本与模板表达式和模板处理器耦合来补充Java现有的字符串文字和文本块,以产生所需的结果。

String name = "Baeldung";
String welcomeText = STR."Welcome to \{name}";
System.out.println(welcomeText);

上面的代码片段打印文本“欢迎来到Baeldung”。

在上面的文本中,我们有一个模板处理器(STR)、一个点字符和一个包含嵌入表达式的模板({name})。在运行时,当模板处理器计算模板表达式时,它将模板中的文字文本与嵌入表达式的值结合起来以产生结果。
STR是Java的模板处理器之一,它会自动导入到所有Java源文件中。Java还提供FMT和RAW模板处理器。

2.4. 虚拟线程(JEP 444)

虚拟线程最初在Java19中作为预览功能引入Java语言,并在Java20中进一步完善。Java21引入了一些新的变化。

虚拟线程是轻量级线程,目的是减少开发高并发应用程序的工作量。传统线程,也称为平台线程,是操作系统线程的瘦包装器。平台线程的主要问题之一是它们在操作系统线程上运行代码并在其整个生命周期中捕获操作系统线程。操作系统线程的数量有限制,这造成了可扩展性瓶颈。

与平台线程一样,虚拟线程也是java. lang.Thread类的实例,但它不绑定到特定的操作系统线程。它在特定的操作系统线程上运行代码,但在整个生命周期内不会捕获线程。因此,许多虚拟线程可以共享操作系统线程来运行它们的代码。

try(var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.rangeClosed(1, 10_000).forEach(i -> {
        executor.submit(() -> {
            System.out.println(i);
            try {
                Thread.sleep(Duration.ofSeconds(1));
            } 
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    });
}

在上面的代码片段中,我们使用了静态newVirtualThreadPerTaskExecutor()方法。此执行器为每个任务创建一个新的虚拟线程,因此在上面的示例中,我们创建了10,000虚拟线程。
Java21引入了虚拟线程的两个显著变化:
虚拟线程现在始终支持线程局部变量。
虚拟线程是通过Thread. BuilderAPI创建的,API也会在其生命周期内受到监控,并且可以在新的线程转储中观察到

2.5.序列集合(JEP 431)

在Java集合框架中,没有集合类型表示具有定义的遇到顺序的元素序列。例如,List和Deque接口定义了遇到顺序,但它们的常见超类型Collection没有。同样,Set没有定义遇到顺序,但LinkedHashSet或SortedSet等子类型可以定义遇到顺序。
Java21引入了三个新的接口来表示序列集合、序列集合和序列映射。

排序集合是一个集合,其元素具有定义的遇到顺序。它有第一个和最后一个元素,它们之间的元素有后继元素和前置元素。排序集是一个没有重复元素的排序集合。排序映射是一个映射,其条目具有定义的遇到顺序。

下图显示了对集合框架层次结构中新引入的接口的改造:
在这里插入图片描述

2.6.密钥封装机制API(JEP 452)

密钥封装是一种使用非对称密钥或公钥加密来保护对称密钥的技术。
传统的方法使用公钥来保护随机生成的对称密钥。然而,这种方法需要填充,这很难证明是安全的。
密钥封装机制(KEM)使用公钥来派生不需要任何填充的对称密钥。
Java21引入了新的KEM API,使应用程序能够使用KEM算法。

  • 18
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值