Java 21 新特性(LTS版本)

这篇具有很好参考价值的文章主要介绍了Java 21 新特性(LTS版本)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Java21新特性

JDK 21 于 2023 年 9 月 19 日 发布,这是一个非常重要的版本,里程碑式。

JDK21 是 LTS(长期支持版),至此为止,目前有 JDK8、JDK11、JDK17 和 JDK21 这四个长期支持版了。

官方文档:OpenJDK Java 21 文档

Java各个版本的文档入口:Java平台,标准版文档

Java各个版本下载:https://jdk.java.net/archive/

JDK 21 共有 15 个新特性:

  • JEP 430:字符串模板 (预览)

  • JEP 431:有序集合

  • JEP 439:分代 ZGC

  • JEP 440:Record 模式

  • JEP 441:switch 模式匹配

  • JEP 442:外部函数和内存 API (第三次预览)

  • JEP 443:未命名模式和变量 (预览)

  • JEP 444:虚拟线程(正式特性)

  • JEP 445:未命名类和 main 方法 (预览)

  • JEP 446:作用域值 (预览)

  • JEP 448:向量 API(第六次孵化)

  • JEP 449:弃用 Windows 32 位 x86 端口

  • JEP 451:准备禁止动态加载代理

  • JEP 452:密钥封装机制 API 安全库

  • JEP 453:结构化并发(预览)

JEP 430:字符串模板 (预览)

String Templates(字符串模板) 目前仍然是 JDK 21 中的一个预览功能。

String Templates 提供了一种更简洁、更直观的方式来动态构建字符串。通过使用占位符${},我们可以将变量的值直接嵌入到字符串中,而不需要手动处理。在运行时,Java 编译器会将这些占位符替换为实际的变量值。并且,表达式支持局部变量、静态/非静态字段甚至方法、计算结果等特性。

该特性处理字符串的新方法称为:Template Expressions,即:模版表达式。它是 Java 中的一种新型表达式,不仅可以执行字符串插值,还可以编程,从而帮助开发人员安全高效地组成字符串。此外,模板表达式并不局限于组成字符串——它们可以根据特定领域的规则将结构化文本转化为任何类型的对象。

该特性主要目的是为了提高在处理包含多个变量和复杂格式化要求的字符串时的可读性和编写效率。

它的设计目标是:

  • 通过简单的方式表达混合变量的字符串,简化 Java 程序的编写。
  • 提高混合文本和表达式的可读性,无论文本是在单行源代码中(如字符串字面量)还是跨越多行源代码(如文本块)。
  • 通过支持对模板及其嵌入式表达式的值进行验证和转换,提高根据用户提供的值组成字符串并将其传递给其他系统(如构建数据库查询)的 Java 程序的安全性。
  • 允许 Java 库定义字符串模板中使用的格式化语法(java.util.Formatter ),从而保持灵活性。
  • 简化接受以非 Java 语言编写的字符串(如 SQL、XML 和 JSON)的 API 的使用。
  • 支持创建由字面文本和嵌入式表达式计算得出的非字符串值,而无需通过中间字符串表示。

Java 在没有 String Templates 之前,我们通常使用字符串拼接或格式化方法来构建字符串:

//concatenation
message = "Greetings " + name + "!";

//String.format()
message = String.format("Greetings %s!", name);  //concatenation

//MessageFormat
message = new MessageFormat("Greetings {0}!").format(name);

//StringBuilder
message = new StringBuilder().append("Greetings ").append(name).append("!").toString();

有String Templates 后

Java 目前支持三种模板处理器:

  • STR:自动执行字符串插值,即将模板中的每个嵌入式表达式替换为其值(转换为字符串)。
  • FMT:和 STR 类似,但是它还可以接受格式说明符,这些格式说明符出现在嵌入式表达式的左边,用来控制输出的样式
  • RAW:不会像 STR 和 FMT 模板处理器那样自动处理字符串模板,而是返回一个 StringTemplate 对象,这个对象包含了模板中的文本和表达式的信息

除了 JDK 自带的三种模板处理器外,你还可以实现 StringTemplate.Processor 接口来创建自己的模板处理器。

STR 模板处理器

STR 是 Java 平台定义的一种模板处理器。它通过用表达式的值替换模板中的每个嵌入表达式来执行字符串插值。使用 STR 的模板表达式的求值结果是一个字符串。

STR 是一个公共静态 final 字段,会自动导入到每个 Java 源文件中。

我们先看一个简单的例子:

    @Test
    public void STRTest() {
        String sk = "Java 新特性";
        String str1 = STR."\{sk},就是牛";
        System.out.println(str1);
    }
// 结果.....
Java 新特性,就是牛

上面的 STR."\{sk},就是牛" 就是一个模板表达式,它主要包含了三个部分:

  • 模版处理器:STR
  • 包含内嵌表达式(\{blog})的模版
  • 通过.把前面两部分组合起来,形式如同方法调用

当模版表达式运行的时候,模版处理器会将模版内容与内嵌表达式的值组合起来,生成结果。

这个例子只是 STR模版处理器一个很简单的功能,它可以做的事情有很多。

数学运算

比如上面的 x + y = ?

    @Test
    public void STRTest() {
        int x = 1,y =2;
        String str = STR."\{x} + \{y} = \{x + y}";
        System.out.println(str);
    }

这种写法是不是简单明了了很多?

调用方法

STR模版处理器还可以调用方法,比如:

String str = STR."今天是:\{ LocalDate.now()} ";

当然也可以调用我们自定义的方法:

    @Test
    public void STRTest() {
        String str = STR."\{getSkStr()},就是牛";
        System.out.println(str);
    }

    public String getSkStr() {
        return "Java 新特性";
    }

访问成员变量

STR模版处理器还可以访问成员变量,比如:

public record User(String name,Integer age) {
}

@Test
public void STRTest() {
  User user = new User("大明哥",18);
  String str = STR."\{user.name()}今年\{user.age()}";
  System.out.println(str);
}

注意点

需要注意的是,字符串模板表达式中的嵌入表达式数量没有限制,它从左到右依次求值,就像方法调用表达式中的参数一样。例如:

    @Test
    public void STRTest() {
        int i = 0;
        String str = STR."\{i++},\{i++},\{i++},\{i++},\{i++}";
        System.out.println(str);
    }
// 结果......
0,1,2,3,4

同时,表达式中也可以嵌入表达式:

    @Test
    public void STRTest() {
        String name = "大明哥";
        String sk = "Java 新特性";
        String str = STR."\{name}的\{STR."\{sk},就是牛..."}";
        System.out.println(str);
    }
// 结果......
大明哥的Java 新特性,就是牛...

但是这种嵌套的方式会比较复杂,容易搞混,一般不推荐。

FMT 模板处理器

FMT 是 Java 定义的另一种模板处理器。它除了与STR模版处理器一样提供插值能力之外,还提供了左侧的格式化处理。下面我们来看看他的功能。比如我们要整理模式匹配的 Switch 表达在 Java 版本中的迭代,也就是下面这个表格

Java 版本 更新类型 JEP 更新内容
Java 17 第一次预览 JEP 406 引入模式匹配的 Swith 表达式作为预览特性。
Java 18 第二次预览 JEP 420 对其做了改进和细微调整
Java 19 第三次预览 JEP 427 进一步优化模式匹配的 Swith 表达式
Java 20 第四次预览 JEP 433
Java 21 正式特性 JEP 441 成为正式特性

如果使用 STR 模板处理器,代码如下:

    @Test
    public void STRTest() {
        SwitchHistory[] switchHistories = new SwitchHistory[]{
                new SwitchHistory("Java 17","第一次预览","JEP 406","引入模式匹配的 Swith 表达式作为预览特性。"),
                new SwitchHistory("Java 18","第二次预览","JEP 420","对其做了改进和细微调整"),
                new SwitchHistory("Java 19","第三次预览","JEP 427","进一步优化模式匹配的 Swith 表达式"),
                new SwitchHistory("Java 20","第四次预览","JEP 433",""),
                new SwitchHistory("Java 21","正式特性","JEP 441","成为正式特性"),
        };

        String history = STR."""
                Java 版本     更新类型    JEP 更新内容
                \{switchHistories[0].javaVersion()} \{switchHistories[0].updateType()} \{switchHistories[0].jep()} \{switchHistories[0].content()}
                \{switchHistories[1].javaVersion()} \{switchHistories[1].updateType()} \{switchHistories[1].jep()} \{switchHistories[1].content()}
                \{switchHistories[2].javaVersion()} \{switchHistories[2].updateType()} \{switchHistories[2].jep()} \{switchHistories[2].content()}
                \{switchHistories[3].javaVersion()} \{switchHistories[3].updateType()} \{switchHistories[3].jep()} \{switchHistories[3].content()}
                \{switchHistories[4].javaVersion()} \{switchHistories[4].updateType()} \{switchHistories[4].jep()} \{switchHistories[4].content()}
                """;
        System.out.println(history);
    }

得到的效果是这样的:

Java 版本     更新类型    JEP 更新内容
Java 17 第一次预览 JEP 406 引入模式匹配的 Swith 表达式作为预览特性。
Java 18 第二次预览 JEP 420 对其做了改进和细微调整
Java 19 第三次预览 JEP 427 进一步优化模式匹配的 Swith 表达式
Java 20 第四次预览 JEP 433 
Java 21 正式特性 JEP 441 成为正式特性

是不是很丑?完全对不齐,没法看。为了解决这个问题,就可以采用FMT模版处理器,在每一列左侧定义格式:

   @Test
    public void STRTest() {
        SwitchHistory[] switchHistories = new SwitchHistory[]{
                new SwitchHistory("Java 17","第一次预览","JEP 406","引入模式匹配的 Swith 表达式作为预览特性。"),
                new SwitchHistory("Java 18","第二次预览","JEP 420","对其做了改进和细微调整"),
                new SwitchHistory("Java 19","第三次预览","JEP 427","进一步优化模式匹配的 Swith 表达式"),
                new SwitchHistory("Java 20","第四次预览","JEP 433",""),
                new SwitchHistory("Java 21","正式特性","JEP 441","成为正式特性"),
        };

        String history = FMT."""
                Java 版本     更新类型        JEP             更新内容
                %-10s\{switchHistories[0].javaVersion()}  %-9s\{switchHistories[0].updateType()} %-10s\{switchHistories[0].jep()} %-20s\{switchHistories[0].content()}
                %-10s\{switchHistories[1].javaVersion()}  %-9s\{switchHistories[1].updateType()} %-10s\{switchHistories[1].jep()} %-20s\{switchHistories[1].content()}
                %-10s\{switchHistories[2].javaVersion()}  %-9s\{switchHistories[2].updateType()} %-10s\{switchHistories[2].jep()} %-20s\{switchHistories[2].content()}
                %-10s\{switchHistories[3].javaVersion()}  %-9s\{switchHistories[3].updateType()} %-10s\{switchHistories[3].jep()} %-20s\{switchHistories[3].content()}
                %-10s\{switchHistories[4].javaVersion()}  %-9s\{switchHistories[4].updateType()} %-10s\{switchHistories[4].jep()} %-20s\{switchHistories[4].content()}
                """;
        System.out.println(history);
    }

输出如下:

Java 版本     更新类型        JEP             更新内容
Java 17     第一次预览     JEP 406    引入模式匹配的 Swith 表达式作为预览特性。
Java 18     第二次预览     JEP 420    对其做了改进和细微调整         
Java 19     第三次预览     JEP 427    进一步优化模式匹配的 Swith 表达式
Java 20     第四次预览     JEP 433                        
Java 21     正式特性       JEP 441    成为正式特性  

JEP 431:有序集合

我们先看在 Java 21 之前,访问Java中集合的第一个和最后一个元素的方式:

集合 获取第一个元素 获取最后一个元素
List list.get(0) list.get(list.size() - 1)
Deque deque.getFirst() deque.getLast()
SortedSet sortedSet.first() sortedSet.last()

三个集合提供了三类不同的使用方法,非常混乱。为了解决这种混乱,Java 21 引入有序集合,旨在解决访问Java中各种集合类型的第一个和最后一个元素需要非统一且麻烦处理场景。

JDK 21 引入了一种新的集合类型:Sequenced Collections(序列化集合,也叫有序集合),这是一种具有确定出现顺序(encounter order)的集合(无论我们遍历这样的集合多少次,元素的出现顺序始终是固定的)。序列化集合提供了处理集合的第一个和最后一个元素以及反向视图(与原始集合相反的顺序)的简单方法。

Sequenced Collections 包括以下三个接口:

  • SequencedCollection
  • SequencedSet
  • SequencedMap

java 21,# java各版本新特性,Java21新特性

SequencedCollection

SequencedCollection 接口继承了 Collection接口, 提供了在集合两端访问、添加或删除元素以及获取集合的反向视图的方法。

interface SequencedCollection<E> extends Collection<E> {
  // New Method
  SequencedCollection<E> reversed();

  // Promoted methods from Deque<E>

  void addFirst(E);
  void addLast(E);

  E getFirst();
  E getLast();

  E removeFirst();
  E removeLast();
}

ListDeque 接口实现了SequencedCollection 接口。

这里以 ArrayList 为例,演示一下实际使用效果:

ArrayList<Integer> arrayList = new ArrayList<>();

arrayList.add(1);   // List contains: [1]

arrayList.addFirst(0);  // List contains: [0, 1]
arrayList.addLast(2);   // List contains: [0, 1, 2]

Integer firstElement = arrayList.getFirst();  // 0
Integer lastElement = arrayList.getLast();  // 2

List<Integer> reversed = arrayList.reversed();
System.out.println(reversed); // Prints [2, 1, 0]

SequencedSet

SequencedSet接口直接继承了 SequencedCollection 接口并重写了 reversed() 方法。

interface SequencedSet<E> extends SequencedCollection<E>, Set<E> {
    SequencedSet<E> reversed();
}

SortedSetLinkedHashSet 实现了SequencedSet接口。

这里以 LinkedHashSet 为例,演示一下实际使用效果:

LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<>(List.of(1, 2, 3));

Integer firstElement = linkedHashSet.getFirst();   // 1
Integer lastElement = linkedHashSet.getLast();    // 3

linkedHashSet.addFirst(0);  //List contains: [0, 1, 2, 3]
linkedHashSet.addLast(4);   //List contains: [0, 1, 2, 3, 4]

System.out.println(linkedHashSet.reversed());   //Prints [5, 3, 2, 1, 0]

SequencedMap

SequencedMap 接口继承了 Map接口, 提供了在集合两端访问、添加或删除键值对、获取包含 key 的 SequencedSet、包含 value 的 SequencedCollection、包含 entry(键值对) 的 SequencedSet以及获取集合的反向视图的方法。

interface SequencedMap<K,V> extends Map<K,V> {
  // New Methods

  SequencedMap<K,V> reversed();

  SequencedSet<K> sequencedKeySet();
  SequencedCollection<V> sequencedValues();
  SequencedSet<Entry<K,V>> sequencedEntrySet();

  V putFirst(K, V);
  V putLast(K, V);


  // Promoted Methods from NavigableMap<K, V>

  Entry<K, V> firstEntry();
  Entry<K, V> lastEntry();

  Entry<K, V> pollFirstEntry();
  Entry<K, V> pollLastEntry();
}

SortedMapLinkedHashMap 实现了SequencedMap 接口。

这里以 LinkedHashMap 为例,演示一下实际使用效果:

LinkedHashMap<Integer, String> map = new LinkedHashMap<>();

map.put(1, "One");
map.put(2, "Two");
map.put(3, "Three");

map.firstEntry();   //1=One
map.lastEntry();    //3=Three

System.out.println(map);  //{1=One, 2=Two, 3=Three}

Map.Entry<Integer, String> first = map.pollFirstEntry();   //1=One
Map.Entry<Integer, String> last = map.pollLastEntry();    //3=Three

System.out.println(map);  //{2=Two}

map.putFirst(1, "One");     //{1=One, 2=Two}
map.putLast(3, "Three");    //{1=One, 2=Two, 3=Three}

System.out.println(map);  //{1=One, 2=Two, 3=Three}
System.out.println(map.reversed());   //{3=Three, 2=Two, 1=One}

JEP 439:分代 ZGC

JDK21 中对 ZGC 进行了功能扩展,增加了分代 GC 功能。不过,默认是关闭的,需要通过配置打开:

// 启用分代ZGC
java -XX:+UseZGC -XX:+ZGenerational ...

在未来的版本中,官方会把 ZGenerational 设为默认值,即默认打开 ZGC 的分代 GC。在更晚的版本中,非分代 ZGC 就被移除。

In a future release we intend to make Generational ZGC the default, at which point -XX:-ZGenerational will select non-generational ZGC. In an even later release we intend to remove non-generational ZGC, at which point the ZGenerational option will become obsolete.

在将来的版本中,我们打算将 Generational ZGC 作为默认选项,此时-XX:-ZGenerational 将选择非分代 ZGC。在更晚的版本中,我们打算移除非分代 ZGC,此时 ZGenerational 选项将变得过时。

分代 ZGC 可以显著减少垃圾回收过程中的停顿时间,并提高应用程序的响应性能。这对于大型 Java 应用程序和高并发场景下的性能优化非常有价值。

JEP 440:Record 模式

记录模式在 Java 19 进行了第一次预览, 由 JEP 405 提出。JDK 20 中是第二次预览,由 JEP 432 提出。最终,记录模式在 JDK21 顺利转正。

Java 20 新特性已经详细介绍过记录模式,这里就不重复了。

JEP 441:switch 模式匹配

增强 Java 中的 switch 表达式和语句,允许在 case 标签中使用模式。当模式匹配时,执行 case 标签对应的代码。

在下面的代码中,switch 表达式使用了类型模式来进行匹配。

static String formatterPatternSwitch(Object obj) {
    return 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);
        default        -> obj.toString();
    };
}

switch 模式匹配在Java20中已经是第四次预览,在Java21转正。前面页详细介绍过,可看:Java 20 新特性

JEP 442:外部函数和内存 API (第三次预览)

Java 程序可以通过该 API 与 Java 运行时之外的代码和数据进行互操作。通过高效地调用外部函数(即 JVM 之外的代码)和安全地访问外部内存(即不受 JVM 管理的内存),该 API 使 Java 程序能够调用本机库并处理本机数据,而不会像 JNI 那样危险和脆弱。

外部函数和内存 API 在 Java 17 中进行了第一轮孵化,由 JEP 412 提出。Java 18 中进行了第二次孵化,由JEP 419 提出。Java 19 中是第一次预览,由 JEP 424 提出。JDK 20 中是第二次预览,由 JEP 434 提出。JDK 21 中是第三次预览,由 JEP 442 提出。

在 Java 19 新特性 中,有详细介绍到外部函数和内存 API,这里就不再做额外的介绍了。

JEP 443:未命名模式和变量 (预览)

未命名模式和变量使得我们可以使用下划线 _ 表示未命名的变量以及模式匹配时不使用的组件,旨在提高代码的可读性和可维护性。

未命名变量的典型场景是 try-with-resources 语句、 catch 子句中的异常变量和for循环。当变量不需要使用的时候就可以使用下划线 _代替,这样清晰标识未被使用的变量。

try (var _ = ScopedContext.acquire()) {
  // No use of acquired resource
}
try { ... }
catch (Exception _) { ... }
catch (Throwable _) { ... }

for (int i = 0, _ = runOnce(); i < arr.length; i++) {
  ...
}

未命名模式是一个无条件的模式,并不绑定任何值。未命名模式变量出现在类型模式中。

if (r instanceof ColoredPoint(_, Color c)) { ... c ... }

switch (b) {
    case Box(RedBall _), Box(BlueBall _) -> processBox(b);
    case Box(GreenBall _)                -> stopProcessing();
    case Box(_)                          -> pickAnotherBox();
}

JEP 444:虚拟线程(正式特性)

虚拟线程是一项重量级的更新,一定一定要重视!

虚拟线程在 Java 19 中进行了第一次预览,由JEP 425提出。JDK 20 中是第二次预览。最终,虚拟线程在 JDK21 顺利转正。

具体可看:Java19新特性-虚拟线程(第一次预览)

JEP 445:未命名类和 main 方法 (预览)

这个特性主要简化了 main 方法的的声明。对于 Java 初学者来说,这个 main 方法的声明引入了太多的 Java 语法概念,不利于初学者快速上手。

没有使用该特性之前定义一个 main 方法:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

使用该新特性之后定义一个 main 方法:

class HelloWorld {
    void main() {
        System.out.println("Hello, World!");
    }
}

进一步精简(未命名的类允许我们不定义类名):

void main() {
   System.out.println("Hello, World!");
}

JEP 446:作用域值 (预览)

作用域值,Java 20 引入的,但是在 Java 21 还处于预览阶段,具体还是看:Java20新特性

JEP 448:向量 API(第六次孵化)

JEP 448(Vector API(第六次孵化器))结合了对前五轮孵化反馈的增强:在 JDK 20 中发布的 JEP 438(Vector API(第五次孵化器))、在 JDK 19 中发布的 JEP 426(Vector API (第四次孵化器))、在 JDK 18 中发布的 JEP 417(Vector API (第三次孵化器))、在 JDK 17 中发布的 JEP 414(Vector API (第二次孵化器))、在 JDK 16 中作为孵化器模块发布的 JEP 338(Vector API (孵化器))。此功能建议增强 Vector API,以便可以从外部函数和内存 API 定义的MemorySegment中加载和存储 Vector。

JEP 442(外部函数和内存API(第三次预览))基于之前的反馈进行了改进,并提供第三次预览:在 JDK 20 中发布的 JEP 434(外部函数和内存API(第二次预览))、在 JDK 19 中发布的 JEP 424(外部函数和内存API(预览)),以及相关的孵化——在 JDK 18 中发布的 JEP 419(外部函数和内存API(第二孵化器))和在 JDK 17 中发布的 JEP 412(外部函数和内存API(孵化器))。这个特性为 Java 应用程序提供了一个 API,可以通过有效地调用外部函数和安全地访问不受 JVM 管理的外部内存与 Java 运行时之外的代码和数据进行互操作。来自 JEP 434 的更新包括:在Arena接口中集中管理本地段的生命周期、增强的布局路径,使用新元素来解引用地址布局、移除VaList类。

开发人员可能会有兴趣了解外部函数和内存 API 所带来的性能提升,这个 API 预计将成为 JDK 22 的最终特性。

Java19新特性里有介绍其API:Java19新特性

JEP 449:弃用 Windows 32 位 x86 端口

JEP 449旨在弃用 Windows 的 32 位 x86 支持,最终目标是在将来完全删除它。

这种弃用及其未来删除背后的原因主要是技术性的。

为任何系统提供软件总是需要决定您实际想要支持哪些平台。针对不再受支持的平台或版本是可能的,但通常意味着增加支持工作、向后移植、自行修复内容等。

以Windows平台为例,最后一个32位版本于2020年发布,官方支持于2025年10月结束。

如果您知道 64 位 Windows 如何处理 32 位应用程序,您可能想知道为什么不能通过 Windows集成的 WOW64 模拟层来运行 JVM ?嗯,通常可以以这种方式运行应用程序,但性能会急剧下降。

这就是 OpenJDK 团队决定继续弃用的原因,因为它只影响 Java 的未来版本。旧系统仍然可以使用删除之前的所有 Java 版本。

Java 21 中的一项直接更改会影响 JDK 的构建过程,因为默认情况下禁用配置构建的可能性。尝试运行bash ./configure会出现错误:

...
checking compilation type... native
configure: error: The Windows 32-bit x86 port is deprecated and may be removed in a future release. \
Use --enable-deprecated-ports=yes to suppress this error.
configure exiting with result code 1

由于该功能只是被弃用,而不是被删除,因此 OpenJDK 团队添加了新的配置选项(如错误所示),--enable-deprecated-ports=yes以仍然允许配置。但是,会发出警告以强调弃用和未来可能的删除。

$ bash ./configure --enable-deprecated-ports=yes
...
checking compilation type... native
configure: WARNING: The Windows 32-bit x86 port is deprecated and may be removed in a future release.
...
Build performance summary:
* Cores to use:   32
* Memory limit:   96601 MB

The following warnings were produced. Repeated here for convenience:
WARNING: The Windows 32-bit x86 port is deprecated and may be removed in a future release.

补充

Java 21 充满了令人敬畏的新功能,虚拟线程 (JEP 444)的添加就是其中之一。它引入了轻量级(虚拟)线程,这可能会通过减少编写、维护和观察此类应用程序所需的工作量,从而显着改变我们处理 Java 中高吞吐量并发应用程序的方式。它们的开销比传统平台(内核)线程少得多。

然而,在 Windows 32 位 x86 上,由于技术限制,此功能必须回退到内核线程。底层平台的这种缺失功能通常是未来弃用和删除的有力指标。

尽管如此,您仍然可以编写和使用新的线程代码,但在实际操作中却缺少预期的好处。

JEP 451:准备禁止动态加载代理

在Java21中将代理动态加载到正在运行的JVM中时发出警告。

这些警告旨在让用户为将来的版本做好准备,该版本默认情况下不允许动态加载代理,以提高默认情况下的完整性。在启动时加载代理的可服务性工具不会导致在任何版本中发出警告。

1.什么是动态加载代理禁用准备?

动态加载代理禁用准备(Prepare to Disallow the Dynamic Loading of Agents)是一个Java增强提案,其目标是在JVM中禁止动态加载代理。代理是一种能够修改或监视应用程序行为的机制,它可以通过字节码注入来实现。

2.为什么需要动态加载代理禁用准备?

动态加载代理允许开发人员在运行时修改和监视Java应用程序的行为。虽然这对于调试和性能分析等方面非常有用,但也存在潜在的安全风险。恶意代码可能会利用动态加载代理的功能来执行恶意操作,例如窃取敏感信息、篡改数据等。

因此,为了加强Java应用程序的安全性,限制动态加载代理的使用是很有必要的。

3.动态加载代理禁用准备的实现原理

动态加载代理禁用准备的实现涉及到以下几个方面:

3.1 修改ClassLoader

该提案建议修改Java虚拟机的类加载器,以阻止动态加载代理。具体而言,将在java.lang.ClassLoader 类中添加一个新的方法boolean disallowDynamicAgentLoading(),默认返回false。当该方法被调用时,将返回true,表示禁止动态加载代理。

3.2 修改Instrumentation API

为了支持ClassLoader的修改,还需要对Java虚拟机的Instrumentation API进行相应的更改。具体而言,将在java.lang.instrument.Instrumentation 接口中添加一个新的方法boolean isDynamicAgentLoadingAllowed(),默认返回true。当该方法返回false时,表示禁止动态加载代理。

3.3 更新安全管理器

此外,还建议更新Java虚拟机的安全管理器(SecurityManager),以允许检查是否允许动态加载代理。这样可以通过安全策略来控制哪些代码可以使用动态加载代理功能。

4.动态加载代理禁用准备的优点

  • 提高Java应用程序的安全性:禁止动态加载代理可以防止恶意代码利用其功能执行潜在的危险操作。
  • 简化安全配置:通过更新安全管理器和类加载器,可以更方便地控制动态加载代理的使用权限,简化安全配置过程。

5.动态加载代理禁用准备的缺点

  • 可能影响现有代码:如果现有代码依赖于动态加载代理的功能,那么禁用它可能会导致这些代码无法正常工作。因此,在应用该增强提案之前,需要仔细评估现有代码的依赖关系。

6.动态加载代理禁用准备的使用示例

以下是一个简单的示例,展示了如何使用动态加载代理禁用准备:

import java.lang.instrument.Instrumentation;

public class AgentLoader {
    public static void premain(String agentArgs, Instrumentation inst) {
        // 禁止动态加载代理
        if (inst.isDynamicAgentLoadingAllowed()) {
            throw new SecurityException("Dynamic loading of agents is not allowed");
        }

        // 其他初始化操作...
    }
}

在上述示例中,premain方法是Java代理的入口点。通过调用isDynamicAgentLoadingAllowed()方法,可以检查是否允许动态加载代理。如果不允许,则抛出安全异常。

7.动态加载代理禁用准备的使用注意事项

  • 在使用动态加载代理禁用准备之前,需要仔细评估现有代码是否依赖于动态加载代理的功能。
  • 需要更新相关的类加载器和安全管理器来支持禁止动态加载代理的功能。
  • 使用动态加载代理禁用准备时,需要确保应用程序的安全策略能够正确地控制动态加载代理的使用权限。

JEP 452:密钥封装机制 API 安全库

Java21新特性 – 密钥封装机制 API 介绍一种用于密钥封装机制(Key Encapsulation Mechanism,简称KEM)的API,这是一种通过公共加密来保护对称密钥的加密技术。

该提案的一个目标是使应用程序能够使用KEM算法,如RSA密钥封装机制(RSA-KEM)、椭圆曲线集成加密方案(ECIES),以及美国国家标准与技术研究所(NIST)后量子密码学标准化过程的候选算法。

另一个目标是使KEM能够在更高级别的协议(如传输层安全性(TLS))和加密方案(如混合公钥加密(HPKE))中使用。

此外,安全提供商将能够在Java代码或本机代码中实现KEM算法,并包括在RFC 9180中定义的Diffie-Hellman KEM(DHKEM)的实现。

值得注意的是,最初针对 JDK 21 的JEP 404, Generational Shenandoah(实验性)已从 JDK 21 的最终功能集中正式删除。这是由于“审查过程中发现的风险以及缺乏时间”可以执行如此大的代码贡献所需的彻底审查。” Shenandoah 团队决定“尽其所能提供最好的 Generational Shenandoah”,并将寻求以 JDK 22 为目标。

JEP 453:结构化并发(预览)

Java19第一次孵化:JEP 428,Java20里是第二次孵化:JEP 437,在Java21里进行预览,相对于Java20,在这里建议将结构化并发作为java.util.concurrent包中的预览API。唯一显著的变化是 StructuredTaskScope::fork(...)方法返回一个Subtask,而不是Future。

其他的可看:Java20新特性文章来源地址https://www.toymoban.com/news/detail-856524.html

到了这里,关于Java 21 新特性(LTS版本)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java 21 新特性和改进

    Java 21 是 Java 17 之后的下一个 LTS 版本。虚拟线程在 Java 21 中将成为正式功能。可以预期的是,Java 21 会成为一个很流行的 Java 版本。 Java 21 将在 2023 年 9 月 19 日发布。目前 Java 21 包含的内容已经基本确定了。下面来梳理一下 Java 21 中会包含的内容。 虚拟线程 (Virtual Threads)

    2024年02月07日
    浏览(37)
  • 【Java基础系列】JDK21新特性

    💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学习,不断总结,共同进步,活到老学到老 导航 檀越剑指大厂系列:全面总

    2024年02月04日
    浏览(43)
  • Java 21 新特性:Record Patterns

    Record Patterns 第一次发布预览是在JDK 19、随后又在JDK 20中进行了完善。现在,Java 21开始正式推出该特性优化。下面我们通过一个例子来理解这个新特性。 上述代码中定义了一个名为Point的record类(Java 16中的新特性),如果我们想要获取、操作或者打印Point中的x和y的话。就不得

    2024年02月08日
    浏览(47)
  • Java 21新特性-虚拟线程 审核中

    本文翻译自国外论坛 medium,原文地址:https://medium.com/@benweidig/looking-at-java-21-virtual-threads-0ddda4ac1be1 Java 21 版本更新中最重要的功能之一就是虚拟线程 (JEP 444)。这些轻量级线程减少了编写、维护和观察高吞吐量并发应用程序所需的工作量。 正如我的许多其他文章一样,在推出

    2024年02月08日
    浏览(57)
  • Java 21:最新特性、性能改进和语言发展

    🎉欢迎来到Java学习路线专栏~Java 21:最新特性、性能改进和语言发展 ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹 ✨博客主页:IT·陈寒的博客 🎈该系列文章专栏:Java学习路线 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习 🍹文章作者技术和水平有

    2024年02月05日
    浏览(40)
  • Java 21 新特性:switch的模式匹配

    在之前的Java 17新特性中,我们介绍过关于JEP 406: switch的模式匹配,但当时还只是关于此内容的首个预览版本。之后在JDK 18、JDK 19、JDK 20中又都进行了更新和完善。如今,在JDK 21中,该特性得到了最终确定!下面,我们就再正式学习一下该功能! 在以往的switch语句中,对于

    2024年02月08日
    浏览(42)
  • Java 21 新特性:虚拟线程(Virtual Threads)

    在Java 21中,引入了虚拟线程(Virtual Threads)来简化和增强并发性,这使得在Java中编程并发程序更容易、更高效。 虚拟线程,也称为“用户模式线程(user-mode threads)”或“纤程(fibers)”。该功能旨在简化并发编程并提供更好的可扩展性。虚拟线程是轻量级的,这意味着它

    2024年02月08日
    浏览(40)
  • Java/JDK 21正式发布!15个特性一览

    JDK 21已经于2023年9月19日正式发布。本文总结了JDK 21发布的新特性。 根据发布的规划,这次发布的 JDK 21 将是一个长期支持版(LTS 版)。LTS 版每 2 年发布一个,上一次长期支持版是 21 年 9 月发布的 JDK 17。 本版本是Java SE平台21版的参考实现,由Java社区流程中的JSR 396指定。 主

    2024年02月08日
    浏览(57)
  • 【Java 21 新特性】顺序集合(Sequenced Collections)

    引入新的接口表示具有定义的遇到顺序的集合。每个这样的集合都有一个明确定义的第一个元素、第二个元素,依此类推,直到最后一个元素。提供统一的API来访问它的第一个和最后一个元素,并以相反的顺序处理它的元素。 \\\"生活只能向后理解;但必须向前生活。\\\"—基尔克

    2024年02月03日
    浏览(40)
  • 【Java 21 新特性 】顺序集合(Sequenced Collections)

    Java 21 中增加了一种新的集合类型:顺序集合(Sequenced Collections)。 要介绍顺序集合,就首先要说明一下出现顺序(encounter order)。出现顺序指的是在遍历一个集合时,集合中元素的出现顺序。 有些集合类型,有确定的出现顺序,比如  List 。不管遍历多少次这样的集合,其

    2024年02月05日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包