首页 > 其他分享 >JDK 21 的新功能!!

JDK 21 的新功能!!

时间:2024-09-18 22:21:40浏览次数:14  
标签:功能 21 JDK System String 线程 println public out

JDK 21 其实很早之前就发了,具体时间是 2023 年 9 月 19 日,是继之前的 LTS 版本 JDK 17 之后最新的长期支持 (LTS) 版本。以下是 JDK 21 的新功能列表:

  • 虚拟线程

  • 序列集合

  • 记录模式

  • 字符串模板(预览)

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

  • 未命名类和实例主要方法(预览)

  • 作用域值(预览)

  • 结构化并发(预览)

1 虚拟线程

从 Java 代码的角度来看,虚拟线程感觉就像普通线程,但它们没有 1:1 映射到操作系统/平台线程。它是从虚拟线程到载体线程进而到操作系统线程的M:N映射。

有一个所谓的载体线程池,虚拟线程临时映射(“安装”)到该线程池上。一旦虚拟线程遇到阻塞操作,虚拟线程就会从载体线程中移除(“卸载”),并且载体线程可以执行另一个虚拟线程(新的或之前被阻塞的虚拟线程)。

载体线程池是ForkJoinPool

图片

虚拟线程的一些优点:

  • 提高应用程序吞吐量

  • 提高应用程序可用性

  • 减少内存消耗

创建虚拟线程

要创建虚拟线程,我们可以使用 Thread.ofVirtual() 工厂方法并传递可运行对象。

  1. Thread.ofVirtual().start(Runnable);

  2. Thread.ofVirtual().unstarted(Runnable);

如果你想让虚拟线程立即启动,你可以使用start() 方法,它会立即执行传递给它的Runnable start()

如果不希望虚拟线程立即启动,可以使用该unstarted()方法。

创建使用虚拟线程的ExecutorService

我们只需要替换newFixedThreadPoolnewVirtualThreadPerTaskExecutor

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class VirtualThreadExample {

    public static void main(String[] args) {
        ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

        executor.submit(() -> {
            System.out.println(Thread.currentThread().getName())
        });

        executor.shutdown();
    }
}

2 顺序集合

顺序集合为我们提供了defined encounter order(是一种所见即所得的顺序,含义是从队列中取出元素的顺序既是你存放该元素时候的顺序),用于访问第一个和最后一个元素并以相反的顺序迭代。

这意味着我们可以在集合的两端添加、检索或删除元素。

图片

public interface SequencedCollection<E> extends Collection<E> {
    default void addFirst(E e) { ... }
    default void addLast(E e) { ... }
    default E getFirst() { ... }
    default E getLast() { ... }
    default E removeFirst() { ... }
    default E removeLast() { ... }
    SequencedCollection<E> reversed();
}

正如我们所看到的,除了reverse()之外的所有方法都是默认方法并提供默认实现。

这意味着现有的集合类(例如 ArrayList 和 LinkedList)都可以实现此接口,而无需更改其代码。

ArrayList<Integer> list = new ArrayList<>();
        list.add(1); // [1]
        list.addFirst(0); // [0, 1]
        list.addLast(2); // [0, 1, 2]
        list.getFirst(); // 0
        list.getLast(); // 2
        list.reversed(); // [2, 1, 0]

SequencedSet

SequencedSet 接口对于具有有序元素的 Set 非常有用,特别是当您必须执行某些操作(例如检索或删除第一个或最后一个索引处的元素)时。它还提供了一种反转元素的方法。

您还需要知道两个 SequencedSet 对象的比较与其他类型的 Set 相同,不依赖于元素顺序。

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

LinkedHashSet 是 Set 的一个实现,它实现了 SequencedSet 接口。

因此,您可以使用 LinkedHashSet 来创建 SequencedSet。

Set 的其他实现(例如 HashSet 和 TreeSet)未实现该接口。

让我们探索一些示例来演示如何访问第一个和最后一个元素,以及如何使用反向函数:

SequencedSet<String> values = new LinkedHashSet<>();
        values.add("one");
        values.add("two");
        System.out.println(values); // [one, two]

        values.addFirst("zero");
        System.out.println(values); // [zero, one, two]
        values.addFirst("one");
        System.out.println(values); // [one, zero, two]

        values.addLast("three");
        System.out.println(values); // [one, zero, two, three]

        values.removeFirst();
        System.out.println(values); // [zero, two, three]

        SequencedSet<String> reversedSet = values.reversed();
        System.out.println(reversedSet); // [three, two, zero]

        boolean isEqual = values.equals(reversedSet);
        System.out.println(isEqual); // true
        System.out.println(values.hashCode()); // 612888
        System.out.println(reversedSet.hashCode()); // 612888
        System.out.println(values.hashCode() == reversedSet.hashCode()); // true

SequencedMap

如果要使用 SequencedMap 中定义的新方法,则需要使用 Map 实现,例如 LinkedHashMap 或实现 SortedMap 的 Map。

HashMap 不利用 Sequenced Collections,因为它没有定义 defined encounter order(是一种所见即所得的顺序,含义是从队列中取出元素的顺序既是你存放该元素时候的顺序)。

interface SequencedMap<K,V> extends Map<K,V> {
    SequencedMap<K,V> reversed();
    SequencedSet<K> sequencedKeySet();
    SequencedCollection<V> sequencedValues();
    SequencedSet<Entry<K,V>> sequencedEntrySet();
    V putFirst(K, V);
    V putLast(K, V);
    Entry<K, V> firstEntry();
    Entry<K, V> lastEntry();
    Entry<K, V> pollFirstEntry();
    Entry<K, V> pollLastEntry();
}

在下面的示例中,正如您所看到的,我们可以通过firstEntry()lastEntry()方法访问第一个和最后一个元素。

pollFirstEntry()方法将删除并返回第一个键值元素,如果映射为空,则返回 null。

此外,调用reverse()只会比较元素,而不依赖于它们的顺序。

SequencedMap<String, Integer> myMap = new LinkedHashMap<>();
        myMap.put("one", 1);
        myMap.put("two", 2);
        System.out.println(myMap); // {one=1, two=2}

        Entry<String, Integer> firstEntry = myMap.firstEntry();
        System.out.println(firstEntry); // one=1

        Entry<String, Integer> lastEntry = myMap.lastEntry();
        System.out.println(lastEntry); // two=2

        myMap.putFirst("zero", 0);
        System.out.println(myMap); // {zero=0, one=1, two=2}
        myMap.putFirst("one", -1);
        System.out.println(myMap); // {one=-1, zero=0, two=2}

        Entry<String, Integer> polledFirstEntry = myMap.pollFirstEntry();
        System.out.println(polledFirstEntry); // one=-1
        System.out.println(myMap); // {zero=0, two=2}

        SequencedMap<String, Integer> reversedMap = myMap.reversed();
        System.out.println(reversedMap); // {two=2, zero=0}

        boolean isEqual = myMap.equals(reversedMap);
        System.out.println(isEqual); // true
        System.out.println(myMap.hashCode()); // 692224
        System.out.println(reversedMap.hashCode()); // 692224
        System.out.println(myMap.hashCode() == reversedMap.hashCode()); // true

3 字符串模板

这是预览功能,默认禁用,我们需要使用

--enable-preview启用字符串模板。

首先,在深入探讨字符串模板之前,我将探讨一些用于组合字符串的技术。

+(加号)运算符: 最大的缺点是每次使用 + 运算符时都会创建一个新字符串。

StringBuffer 和 StringBuilder: StringBuffer 是线程安全的,而 StringBuilder 是在 Java 5 中添加的,性能更高,但不是线程安全的替代方案。

它们的主要缺点是冗长,尤其是对于更简单的字符串:

var greeting = new StringBuilder()
        .append("Hello, welcome ")
        .append(name)
        .toString();

String::format 和 String::formatter: 它们允许可重用模板,但它们要求我们指定格式并以正确的顺序提供变量。

var format = "Good morning %s, It's a beautiful day!";
        var text = String.format(format, name);
// Java 15+
        var text = format.formatter(name);

尽管我们节省了字符串分配的数量,但现在 JVM 必须解析/验证模板字符串。

java.text.MessageFormat: 与String格式相同,但更详细

 var format = new MessageFormat("Good morning {0}, It's a beautiful day!");
        var greeting = format.format(name);

现在我们有字符串模板来拯救

它简单、简洁,处理字符串的新方法称为模板表达式。它们可以执行插值,还为我们提供了组合字符串的灵活性,并将结构化文本转换为任何对象,而不仅仅是字符串。

模板表达式由三个组成部分组成:

  • 模板处理器:Java 提供了两种用于执行字符串插值的模板处理器:STR 和 FMT

  • 包含包装表达式的模板,如 {name}

  • 点 (.) 字符

以下是一些关于如何将字符串模板与模板处理器一起使用的示例:

package com.mina.stringtemplates;

import static java.util.FormatProcessor.FMT;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class StringTemplateExamples {

    public static String greeting(String firstName, String lastName) {
        return STR."Hello! Good morning \{ firstName } \{ lastName }" ;
    }

    public static String multiplyWithArithmeticExpressions(int a, int b) {
        return STR."\{ a } times \{ b } = \{ a * b }" ;
    }

    public static String multiplyWithJavaExpression(int a, int b) {
        return STR."\{ a } times \{ b } = \{ Math.multiplyExact(a, b) }" ;
    }

    //  multiplication with floating point numbers rounded to two decimal places using the FMT template processor
    public static String multiplyFloatingNumbers(double a, double b) {
        return FMT."%.2f\{ a } times %.2f\{ b } = %.2f\{ a * b }" ;
    }

    public static String getErrorResponse(int httpStatus, String errorMessage) {
        return STR."""
                {
                  "httpStatus": \{ httpStatus },
                  "errorMessage": "\{ errorMessage }"
                }""" ;
    }

    public static String getCurrentDate() {
        return STR."Today's date: \{
        LocalDate.now().format(
                DateTimeFormatter.ofPattern("yyyy-MM-dd")
        ) }" ;
}
}

4 记录模式

记录模式匹配是一种在单个步骤中匹配记录类型并访问其组件的方法。

我们用它来测试一个值是否是记录类类型的实例,如果是,则对其组件值执行模式匹配。

下面的示例测试是否是具有记录模式transaction的记录实例TransactionTransaction(String type, double amount)

package com.mina.recordpattern;

public class RecordPatternExample {

    // I'm using "_" for readability here, this won't compile
    public static String getTransactionType(Transaction transaction) {
        return switch (transaction) {
            case null -> throw new IllegalArgumentException("Transaction can not be null.");
            case Transaction(String type, double amount) when type.equals("Deposit") && amount > 0 -> "Deposit";
            case Transaction(String type, _) when type.equals("Withdrawal") -> "Withdrawal";
                default -> "Unknown transaction type";
        };
    }

    record Transaction(String type, double amount) {

    }
}

如果事务为空,会发生什么?你是对的——抛出了一个空指针异常。这也是Java 21中的情况,但是现在我们可以通过写case null->来显式地使用null case,这样可以避免NullPointerException。

保护模式:也可以保护特定情况。例如,我们使用when关键字来检查相等性。

5 switch 模式匹配

switch模式匹配在 Java 17 中作为预览功能引入,并在 Java 21 中永久保留。

语句switch将控制转移到多个语句或表达式之一,具体取决于其选择器表达式的值(可以是任何类型),并且case标签可以具有模式。

它检查其选择器表达式是否与模式匹配,与测试其选择器表达式是否完全等于常量相比,这更具可读性和灵活性。

package com.mina.switchpatternmatching;

import com.mina.switchpatternmatching.SwitchPatternMatchingExample.Transaction.Deposit;
import com.mina.switchpatternmatching.SwitchPatternMatchingExample.Transaction.Withdrawal;

public class SwitchPatternMatchingExample {

    public static String getTransactionType(Transaction transaction) {
        return switch (transaction) {
            case null:
                throw new IllegalArgumentException("Transaction can't be null.");
            case Deposit deposit when deposit.getAmount() > 0: //  Guarded pattern with when clause
                yield "Deposit";
            case Withdrawal withdrawal:
                yield "Withdrawal";
            default:
                yield "Unknown transaction type";
        };
    }

    sealed class Transaction permits Deposit, Withdrawal {

        private double amount;

        public Transaction(double amount) {
            this.amount = amount;
        }

        public double getAmount() {
            return amount;
        }


        final class Withdrawal extends Transaction {

            public Withdrawal(double amount) {
                super(amount);
            }
        }

        final class Deposit extends Transaction {

            public Deposit(double amount) {
                super(amount);
            }
        }
    }
}

 ——EOF——


福利:

扫码回复【酒店】可免费领取酒店管理系统源码

标签:功能,21,JDK,System,String,线程,println,public,out
From: https://blog.csdn.net/java_121388/article/details/142345448

相关文章

  • 213. 打家劫舍 II
    题目链接213.打家劫舍II思路动态规划-打家劫舍-简单变体题解链接简洁写法!直接调用198题代码!(Python/Java/C++/Go/JS/Rust)关键点可以分为两种情况讨论:1.选第一个位置2.不选第一个位置时间复杂度\(O(n)\)空间复杂度\(O(1)\)代码实现:classSolu......
  • LOJ #3490. 「JOISC 2021 Day2」逃跑路线
    Description在IOI王国,人们使用Byou作为时间单位。IOI王国中的一天被分为了\(S\)个时间单位。每天从最开始经过\(x\(0\lex<S)\)Byou后的时间称为时刻\(x\)。IOI王国由\(N\)个城市组成,以\(0\)到\(N-1\)编号。其中有\(M\)条双向道路连接某些城市,以\(0\)......
  • 系统地掌握 SecureCRT 的基本使用;深入掌握 SecureCRT 的各项功能与技巧。深入掌握 Sec
    secureCRT.exe是一个用于安全远程访问的终端仿真程序。它主要用于通过SSH、Telnet和其他协议连接到远程计算机和网络设备,以实现安全的命令行操作。功能和用途安全连接:通过SSH加密协议提供安全的远程访问,保护数据传输。终端仿真:支持多种终端类型,如VT100、VT102、......
  • P2163 [SHOI2007] 园丁的烦恼
    中学的时候年轻气盛,应该拿主席树把这道题艹过去了。正好复习离线二维数点,再做了一遍。我们把询问差分安排到x轴上,然后y轴用树状数组统计即可。注意到此题要离散化,但是询问中的x可能不在原序列中。不过这不要紧,记得二分完减一就好。constintN=5e5+5,S=1e7+5;intn,m......
  • ICPC2021 沈阳站 M String Problem 题解 | 十种做法一网打尽 , 一道题带你回顾字符串科
    题目传送门题意给定一个字符串,求每个前缀的字典最大序子串。注意到:对于每个前缀$s_{[1,i]}$,字典序最大子串的右边界一定是\(i\)。随着着\(i\)的增大,字典序最大子串的左边界一定是单调不减的。解法不分先后。后缀数组SASA&SAM后缀数组&后缀自动机SA对所有......
  • X-ray设备的CNC自动检测功能有什么用?
    CNC自动检测:程序根据编程设定路径对X-ray设备进行逐个成像检测并按照设定标准给出测量数据判定结果。在X射线设备中引入CNC自动检测功能,可以显著提升产品质量检测的效率和准确性。通过编程设定的路径,设备能够对每一个产品进行逐一成像检测,并根据预先设定的标准生成测量数据,从......
  • JDK21中找不到 javax.annotation.Resource 了?
    在JDK9及以后版本,特别是到JDK21,javax.annotation.Resource这样的类已经不再包含在标准的JDK中。原因是从JDK9开始,Java进行了模块化(ProjectJigsaw),并移除了部分与JavaEE(现在称为JakartaEE)相关的包,例如javax.annotation。为什么会找不到javax.annotation.Resourc......
  • 21LTR靶机(漏洞复现)
    网卡配置访问网页端口扫描nmap-sV-p-192.168.2.1200目录扫描右键检查,发现用户名和密码尝试ssh连接,连接失败尝试ftp连接,连接成功发现一个backup_log.php文件nc-e/bin/sh192.168.2.1285555python-c'importpty;pty.spawn......
  • JDK的选择安装和下载
    搭建Java开发环境要使用Java首先必须搭建Java的开发环境;Java的产品叫JDK(JavaDevelopmentKit:Java开发工具包),必须安装JDK才能使用Java。JDK发展史那么这么多JDK,应该使用哪个版本,此处可以看到JDK-8、JDK-11、JDK-17后面都有标记LTS,LTS即“long-trrmsupport:长期支持版”,即......
  • Day23笔记-Day21和Day22作业讲解&单例类
    Day22作业讲解'''学生类Student:属性:学号,姓名,年龄,性别,成绩​班级类Grade:属性:班级名称,班级中的学生【使用列表存储学生】​方法:1.查看该班级中的所有学生的信息2.查看指定学号的学生信息3.查看......