JDK 新特性深度分析,但我用Java 8

官方文档链接:https://openjdk.org/projects/jdk/21/

下载链接:https://www.oracle.com/cn/java/technologies/downloads/#jdk21-windows

1、介绍

JDK21 是2023.09.19发布的正式版

其他版本的含义:

  • Alpha:软件或系统的内部测试版本,仅内部人员使用。一般不向外部发布,通常会有很多 Bug,除非你也是测试人员,否则不建议使用,alpha 就是 α,是希腊字母的第一位,表示最初级的版本,beta 就是 β,alpha 版就是比 beta 还早的测试版,一般都是内部测试的版本。
  • Beta:公开测试版。β 是希腊字母的第二个,顾名思义,这一版本通常是在 Alpha 版本后,该版本相对于 Alpha 版已有了很大的改进,消除了严重的错误,但还是存在着一缺陷,需要经过多次测试来进一步消除。这个阶段的版本会一直加入新的功能。
  • Gamma: 软件或系统接近于成熟的版本,只需要做一些小的改进就能发行。是 beta 版做过一些修改,成为正式发布的候选版本。
  • RC:Release Candidate,发行候选版本。和 Beta 版最大的差别在于 Beta 阶段会一直加入新的功能,但是到了 RC 版本,几乎就不会加入新的功能了,而主要着重于除错。RC 版本是最终发放给用户的最接近正式版的版本,发行后改正 bug 就是正式版了,就是正式版之前的最后一个测试版。
  • GA:General Available,正式发布的版本,这个版本就是正式的版本。在国外都是用 GA 来说明 release 版本的。比如:MySQL Community Server 5.7.21 GA 这是 MySQL Community Server 5.7 第 21 个发行稳定的版本,GA 意味着 General Available,也就是官方开始推荐广泛使用了。
  • Release:这个版本通常就是所谓的"最终版本",在前面版本的一系列测试版之后,终归会有一个正式版本,是最终交付用户使用的一个版本,该版本有时也称为标准版。一般情况下,Release 不会以单词形式出现在软件封面上,取而代之的是符号®。
  • Stable:稳定版。在开源软件中,都有 stable 版,这个就是开源软件的最终发行版,用户可以放心大胆的用了。这一版本基于 Beta 版,已知 Bug 都被修复,一般情况下,更新比较慢。

2、新功能

根据官方文档:https://www.infoq.com/news/2023/09/java-21-so-far/

最终的 15 个新功能集(以JEP的形式)可分为四 (4) 类:核心 Java 库Java 语言规范热点安全库,根据官方文档,分为了正式版和预览版,思维导图如下:

正式功能

  1. 虚拟线程
  2. 序列集合
  3. 弃用 Windows 32 位 x86 移植
  4. 准备禁止动态加载代理
  5. 分代 ZGC
  6. switch 模式匹配
  7. 记录模式
  8. 密钥封装机制 API

预览版功能:

  1. 字符串模板(预览)
  2. 外部函数和内存 API(第三次预览)
  3. 未命名模式和变量(预览)
  4. 未命名类和实例主方法(预览)

3、虚拟线程

你发任你发,我用JAVA8

提供了一种更高效、更轻量级的线程模型

1、为什么需要加入虚拟线程

在此之前,我们创建线程后需要销毁线程来释放内存,会造成大量的成本消耗,完美的解决方案就是我们用线程池,通过线程池来管理线程,并且共享线程相当于说我用的时候去租用一个线程。

这样就解决了创建和销毁的成本,但是呢,还有并发量没有解决,线程逐渐增多之后,线程之间会存在频繁切换,切换的成本很高

so 就引入了虚拟线程,使用虚拟线程进行切换,这样成本就相当于只有一个线程在工作

2、使用

代码层面兼容性很好,基本和原来的线程池没有区别

首先创建一个普通线程,实现Runnable接口

java 复制代码
public class ThreadDemo implements Runnable{
    @Override
    public void run() {
        System.out.println("线程名为:" + Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

1、通过Thread直接使用

java 复制代码
Thread thread = Thread.startVirtualThread(new ThreadDemo());

2、使用ofVirtual(),构建器模式启动虚拟线程,您可以设置线程名称、优先级、异常处理和其他配置

java 复制代码
Thread thread = Thread.ofVirtual().name("javaxiaobear").unstarted(new ThreadDemo());

3、通过Executors调用

java 复制代码
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 10_000).forEach(i -> {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            return i;
        });
    });
}  // executor.close() is called implicitly, and waits

//另一种写法
ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor();
Future<?> submit = executorService.submit(new ThreadDemo());
Object javaxiaobear = submit.get();

4、使用工厂模式创建虚拟线程,其实跟ofVirtual差不多

java 复制代码
ThreadFactory factory = Thread.ofVirtual().factory();
Thread thread = factory.newThread(new ThreadDemo());
thread.setName("javaxiaobear");
thread.start();
java 复制代码
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 10_000).forEach(i -> {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            return i;
        });
    });
}  // executor.close() is called implicitly, and waits

4、序列集合

官方文档:https://openjdk.org/jeps/431

Java 的集合框架缺少表示具有定义的遇到顺序的元素序列的集合类型,比如LinkedHashSet获取最后一个元素,就需要遍历整个集合,所以官方就增加了3个接口

有序集合 是其Collection元素具有定义的遇到顺序的集合,有序集合具有第一个和最后一个元素,它们之间的元素具有后继和前驱。排序集合支持两端的通用操作,并且支持从第一个到最后一个以及从最后一个到第一个(即正向和反向)处理元素。

1、有序集合

java 复制代码
interface SequencedCollection<E> extends Collection<E> {
    // new method
    SequencedCollection<E> reversed();
    // methods promoted from Deque
    void addFirst(E);
    void addLast(E);
    E getFirst();
    E getLast();
    E removeFirst();
    E removeLast();
}

2、序列集

java 复制代码
interface SequencedSet<E> extends Set<E>, SequencedCollection<E> {
    SequencedSet<E> reversed();    // covariant override
}

3、序列Map

java 复制代码
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);
    // methods promoted from NavigableMap
    Entry<K, V> firstEntry();
    Entry<K, V> lastEntry();
    Entry<K, V> pollFirstEntry();
    Entry<K, V> pollLastEntry();
}

5、弃用 Windows 32 位 x86 移植

这里就很简单,未来将不支持32位的系统了

6、准备禁止动态加载代理

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

总的来说就是在JVM中禁止动态加载代理

在 JDK 21 中,允许动态加载代理,但 JVM 在发生这种情况时会发出警告。例如:

复制代码
WARNING: A {Java,JVM TI} agent has been loaded dynamically (file:/u/bob/agent.jar)
WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning
WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information
WARNING: Dynamic loading of agents will be disallowed by default in a future release

要允许工具动态加载代理而不发出警告,用户必须-XX:+EnableDynamicAgentLoading在命令行上使用该选项运行。

7、分代 ZGC

ZGC(JEP 333)专为低延迟和高可扩展性而设计,通过扩展 Z 垃圾收集器 ( ZGC ) 来维护年轻对象和老对象的不同,从而提高应用程序性能。这将使 ZGC 能够更频繁地收集年轻对象(这些对象往往会在年轻时死亡)

在 Java 21 中,我们可以这样开启分代 ZGC:

复制代码
java -XX:+UseZGC -XX:+ZGenerational ...

同时,分代 ZGC 中不再需要设置年轻代大小、年轻代进入老年代所需要的 GC 次数、GC 线程数等,ZGC 将这些全部动态化,并在内部自动调优。现在只需要设置一个参数,即最大内存大小 -Xmx

具体详情大家可参考这篇:https://sdl.moe/post/generational-zgc/

8、switch 模式匹配

官方文档:https://openjdk.org/jeps/441

switch 通过表达式和语句的模式匹配增强 Java 编程语言。扩展模式匹配switch允许针对多个模式测试表达式,每个模式都有一个特定的操作,以便可以简洁、安全地表达复杂的面向数据的查询,实际上就是一个语法升级,代码美观了

1、使用

java 复制代码
public class SwitchTest {

    public static void main(String[] args) {
        int i = 88;
        System.out.println("以前写法"+ formatter(i));
        System.out.println(formatterPatternSwitch(i));
    }

    /**
     *  以前写法
     * @param obj
     * @return
     */
    public static String formatter(Object obj) {
        String formatted = "unknown";
        if (obj instanceof Integer i) {
            formatted = String.format("int %d", i);
        } else if (obj instanceof Long l) {
            formatted = String.format("long %d", l);
        } else if (obj instanceof Double d) {
            formatted = String.format("double %f", d);
        } else if (obj instanceof String s) {
            formatted = String.format("String %s", s);
        }
        return formatted;
    }

    /**
     * 现在写法
     * @param obj
     * @return
     */
    public 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();
        };
    }
}

2、空值处理

java 复制代码
/**
 * 之前写法
 * @param s
 */
public static void testFooBarOld(String s) {
    if (s == null) {
        System.out.println("是空值!");
        return;
    }
    switch (s) {
        case "Foo", "Bar" -> System.out.println("Great");
        default           -> System.out.println("javaxiaobear is Good");
    }
}

/**
 * 新特性写法
 * @param s
 */
static void testFooBarNew(String s) {
    switch (s) {
        case null         -> System.out.println("Oops");
        case "Foo", "Bar" -> System.out.println("Great");
        default           -> System.out.println("javaxiaobear is Good");
    }
}

9、记录模式

官方文档:https://openjdk.org/jeps/440

Record Patterns的实现原理主要涉及两个方面:

  • 记录类型
  • 记录类型是一种新的类声明形式,通过record关键字来定义。

模式匹配

模式匹配是指根据给定的模式来匹配某个对象,并执行相应的操作。在Record Patterns中,我们可以使用instance of关键字和模式变量

来进行模式匹配。具体地说,当我们使用Record Patterns进行模式匹配时,编译器会自动为记录类型生成一个模式匹配方法。这个方法

接受一个对象作为参数兰担据给定的模式进行匹配。如果匹配成功,则将字段值绑定到相应的模式变量中,从而可以在后续代码中用。

10、密钥封装机制 API

引入密钥封装机制 (KEM) 的 API,这是一种使用公钥加密来保护对称密钥的加密技术。密钥封装是一种现代加密技术,它使用非对称或公钥加密来保护对称密钥。这样做的传统技术是使用公钥加密随机生成的对称密钥,但这需要填充并且很难证明安全。相反,密钥封装机制 (KEM) 使用公钥的属性来派生相关的对称密钥,这不需要填充。

KEM 由三个功能组成:

  • 密钥对生成函数,返回包含公钥和私钥的密钥对。
  • 密钥封装函数 ,由发送方调用,采用接收方的公钥和加密选项;它返回一个秘密密钥K 和一个密钥封装消息(在 ISO 18033-2 中称为*密文)。*发送方将密钥封装消息发送给接收方。
  • 密钥解封装函数 ,由接收方调用,获取接收方的私钥和接收到的密钥封装消息;它返回密钥K
java 复制代码
import javax.crypto.KEM;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;

public class KEMTest {
    public static void main(String[] args) throws NoSuchAlgorithmException {
        //RSA算法
        KeyPairGenerator instance = KeyPairGenerator.getInstance("RSA");
        //初始化秘钥大小
        instance.initialize(1024);
        //生成密钥对
        KeyPair kp = instance.generateKeyPair();
        //获取公钥
        System.out.println(kp.getPublic());
        //获取私钥
        System.out.println(kp.getPrivate());

    }
}
相关推荐
张张张31213 分钟前
4.2学习总结 Java:list系列集合
java·学习
KATA~16 分钟前
解决MyBatis-Plus枚举映射错误:No enum constant问题
java·数据库·mybatis
xyliiiiiL32 分钟前
一文总结常见项目排查
java·服务器·数据库
shaoing33 分钟前
MySQL 错误 报错:Table ‘performance_schema.session_variables’ Doesn’t Exist
java·开发语言·数据库
腥臭腐朽的日子熠熠生辉1 小时前
解决maven失效问题(现象:maven中只有jdk的工具包,没有springboot的包)
java·spring boot·maven
ejinxian1 小时前
Spring AI Alibaba 快速开发生成式 Java AI 应用
java·人工智能·spring
杉之1 小时前
SpringBlade 数据库字段的自动填充
java·笔记·学习·spring·tomcat
圈圈编码2 小时前
Spring Task 定时任务
java·前端·spring
俏布斯2 小时前
算法日常记录
java·算法·leetcode
27669582922 小时前
美团民宿 mtgsig 小程序 mtgsig1.2 分析
java·python·小程序·美团·mtgsig·mtgsig1.2·美团民宿