Java 21的新特性

发布时间:2023-11-23 10:09
最后更新:2024-09-03 08:45
所属分类:
JVM Java

Java 21是继Java 17之后的一个长期支持版本(LTS),也是一个里程碑版本,其中稳定提供了很多功能。Java 21引入了15个新特性,但是这些新特性大多都是在之前的版本中进行了孵化和预览的,这里拣选这些特性中比较重要且可能比较常用的功能来记录。

Java 21于2023年9月19日发布,推荐在生产环境中采用。

截止到Java 21的发布,现在Java有8、11、17、21四个LTS版本同时共存了。

本系列的文章有:

  1. Java 8的新特性
  2. Java 9的新特性
  3. Java 10的新特性
  4. Java 11的新特性
  5. Java 12的新特性
  6. Java 13的新特性
  7. Java 14的新特性
  8. Java 15的新特性
  9. Java 16的新特性
  10. Java 17的新特性
  11. Java 18的新特性
  12. Java 19的新特性
  13. Java 20的新特性
  14. Java 21的新特性

功能提案

在Java 21中主要增加了以下提案中的功能。

这些提案里的大部分内容都已经在前面几个版本中出现过了,这里只拣选一些稳定下来的和新出现的特性予以记录。

字符串模板

在其他的很多语言中,字符串模板并不是一个新鲜的功能,例如Python中的f字符串,Javascript中的反引号字符串,都可以提供更加简单的把变量内容拼接到字符串中的能力。但是在Java中,长久以来把变量内容放入字符串中,往往依靠字符串拼接和StringBuilder等功能。而且不同的字符串拼接方法的效率也不同,也成为了各类面试题中的常客。

在Java中,将变量内容放入一个字符串,通常会使用以下几种方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 字符串拼接
var message = "Hello " + name + ".";

// 字符串的格式化方法
var message = String.format("Hello %s.", name);

// MessageFormat
var message = new MessageFormat("Hello {0}.").format(name);

// StringBuilder
var message = new StringBuilder().append("Hello ").append(name).append(".").toString();

以上这几种方法基本上都有同样的缺点:冗长且复杂。所以引入字符串模板也是解决这个问题的最好的方案。

出于不同的处理目的,Java引入了三种模板处理器:

  • STR可以自动执行字符串插值,会自动将模板中每个嵌入表达式的值转换成字符串。
  • FMTSTR类似但是提供了格式说明符,允许用来控制嵌入表达式的输出格式。
  • RAW会返回一个StringTemplate对象,用于进行后续的其他处理。

在字符串模板中Java使用\{expression}作为嵌入表达式来嵌入一个动态的内容。例如上面的实例如果使用字符串模板实现就会是以下形式。

1
2
3
4
5
6
7
8
9
// 使用STR处理器
var message = STR."Hello \{name}.";

// 使用FMT处理器增加格式
var message = FMT."Hello %-7s\{name}.";

// 使用RAW处理器
StringTemplate messageTempplate = RAW."Hello \{name}.";
var message = STR.process(messageTemplate);

除了默认的三种字符串模板处理器以外,Java还提供了StringTemplate.Processor接口来允许使用者重建自定义的模板处理器。

有序集合

Java 21引入了一个继承自Collection<T>接口的新集合类型SequencedCollection<T>,用来保证其中的元素顺序。有序集合无论遍历多少次,都可以保证元素的出现顺序。目前有序集合包含了三个接口:SequencedCollection<T>SequencedSet<T>SequencedMap<T>

现在List<T>Deque<T>都已经默认实现了SequencedCollection<T>接口。

有序集合除了提供在集合两端访问的方法以外,还提供了获取集合反向视图的方法。

记录模式与模式匹配

在Java 14中引入的模式匹配switch表达式和在Java 19中引入的记录模式匹配在Java 21中已经成为了稳定特性。其相关资料可以参考之前的文章。

未命名模式和变量

未命名模式和变量是Java 21引入的一项预览功能,它主旨是解决在很多情况下,代码必须创建一个并不需要使用的变量的问题。例如在以下实例中。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
try (var context = ScopedContext.acquire()) {
  // 这里实际上并不需要使用获取到的上下文context
}

try {
} catch (Exception e) {
  // 这里实际上并不需要使用变量e
}

// 以下switch的模式匹配中定义的变量实际上全都未被使用
switch (box) {
  case Box(Red redBall), Box(Yellow yellowBall) -> processWarmColorBox(b);
  case Box(Blue blueBall), Box(Green greenBall) -> processColdColorBox(b);
  default -> pickAnotherBox();
}

未命名模式和变量就是借鉴了其他语言中的_作为占位符来代替这些不需要使用的内容,这样就可以清晰的标注那些不需要使用的内容了。例如上面的实例就会变成以下更加简洁的形式。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
try (var _ = ScopedContext.acquire()) {
  // ...
}

try {
} catch (Exception _) {
  // ...
}

// switch模式中直接判断内容类型即可。
switch (box) {
  case Box(Red _), Box(Yellow _) -> processWarmColorBox(b);
  case Box(Blue _), Box(Green _) -> processColdColorBox(b);
  case Box(_) -> pickAnotherBox();

虚拟线程

虚拟线程在Java 19中首次提出以来,现在在Java 21中已经成功稳定了下来。虚拟线程的使用方法不难,而且虚拟线程的控制与传统线程无异,可参考目前已有的资料快速上手。

未命名类和实例main方法

在传统Java程序中,定义一个main方法需要以下形式。

1
2
3
4
5
public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello World");
  }
}

这种写法非常的繁琐,并且携带了很多无意义的内容,比如定义了一个并没有什么用途的HelloWorld类。

在Java 21引入实例main方法这个预览特性以后,main方法的定义可以被精简成以下形式。

1
2
3
4
5
class HelloWorld {
  void main() {
    System.out.println("Hello World");
  }
}

在使用未命名类的预览特性时,可以更加精简的省略类名的定义。

1
2
3
void main() {
  System.out.println("Hello World");
}

索引标签
JVM
Java
Java 21
新特性
模式匹配
有序集合
虚拟线程
未命名类
未命名模式
字符串模板