一、前言

JDK 21 于 2023 年 9 月发布,作为目前讨论热度最高的JDK,虽然大家都开玩笑说你发任你发,我用Java8,但是作为一个Javaer,对JDK21的新特性还是要有所了解的。

以下是 JDK 21 的新功能列表:

  • 虚拟线程
  • 序列集合
  • 记录模式
  • 字符串模板(预览)
  • 未命名模式和变量(预览)
  • 未命名类和实例主要方法(预览)
  • 作用域值(预览)
  • 结构化并发(预览)

JDK21下载地址:JDK官网

在这里插入图片描述

安装过程在这里就不赘述了,正常【下一步】就行了。

二、新特性体验

1. switch 模式匹配

可以通过switch表达式和语句的模式匹配来增强Java编程语言,可以针对多个模式测试表达式,每个模式都有一个特定的操作,从而可以简洁、安全地表达复杂的面向数据的查询。

1.1 支持返回值,不用写break

示例代码:

public class SwitchTest {

    public static void main(String[] args) {
        String unit = "cm";
        String str = switch (unit) {
            case "cm" -> "厘米";
            case "m" -> "米";
            case "mm" -> "毫米";
            case "km" -> "千米";
            default -> "错误";
        };
        System.out.println(str);
    }
}

测试结果:

在这里插入图片描述

注意:如果执行结果乱码,可以参考如下操作进行:

  1. 增加VM参数

    在这里插入图片描述

  2. 修改文件编码

    在这里插入图片描述

1.2 如果需要执行多行代码再返回,可使用yield关键字

示例代码:

public class SwitchTest {

    public static void main(String[] args) {
        String unit = "cm";
        String str = switch (unit) {
            case "cm" -> {
                System.out.println("我在测试呢...");
                yield "厘米";
            }
            case "m" -> "米";
            case "mm" -> "毫米";
            case "km" -> "千米";
            default -> "错误";
        };
        System.out.println(str);
    }
}
1.3 多值匹配

示例代码:

public class SwitchTest {

    public static void main(String[] args) {
        String unit = "cm";
        String str = switch (unit) {
            case "cm", "m" -> "厘米";
            case "mm" -> "毫米";
            case "km" -> "千米";
            default -> "错误";
        };
        System.out.println(str);
    }
}
1.4 null值处理

示例代码:

public class SwitchTest {

    public static void main(String[] args) {
        String unit = null;
        String str = switch (unit) {
            case "cm", "m" -> "厘米";
            case "mm" -> "毫米";
            case "km" -> "千米";
            case null -> "未知";
            default -> "错误";
        };
        System.out.println(str);
    }
}
1.5 匹配增强

示例代码:

public class SwitchTest {

    public static void main(String[] args) {
        Double obj = 0.0d;
        String str = 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();
        };
        System.out.println(str);
    }
}

2. 记录模式

记录模式,也就是记录模式匹配,英文为“Record Patterns”,记录模式匹配是指自动匹配Record记录类,从而简化代码。Record记录会自动生成了构造函数、getter、equals、hashCode、toString等方法,简化代码的编写,类似于lombok插件的@Data注解,但是对象属性只读,只有get方法,没有set方法。

  • 使用class

    public class User {
        private String name;
    
        private Integer age;
    
        public User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
    
        public Integer getAge() {
            return age;
        }
        
    }
    
  • 使用record

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

3. 字符串模板

示例代码:

public class StrTest {

    public static void main(String[] args) {
        String name = "JDK21";
        String message = STR."Hello \{name}!";
        System.out.println(message);
    }
}

注意这是预览功能,默认禁用,我们需要使用--enable-preview启用字符串模板。

在Idea中,我们需要额外设置:

在这里插入图片描述

--enable-preview --source 21 -Xlint:preview

4. 顺序集合

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

  • List

    import java.util.LinkedHashSet;
    import java.util.SequencedSet;
    
    public class ListTest {
        public static void main(String[] args) {
            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]
            
    
            SequencedSet<String> reversedSet = values.reversed();
            System.out.println(reversedSet); // [three, two, zero, one]
        }
    }
    
  • Map

    import java.util.LinkedHashMap;
    import java.util.Map;
    import java.util.SequencedMap;
    
    public class MapTest {
        public static void main(String[] args) {
            SequencedMap<String, Integer> myMap = new LinkedHashMap<>();
            myMap.put("one", 1);
            myMap.put("two", 2);
            System.out.println(myMap); // {one=1, two=2}
    
            Map.Entry<String, Integer> firstEntry = myMap.firstEntry();
            System.out.println(firstEntry); // one=1
    
            Map.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}
    
            Map.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}
        }
    }
    

5. 虚拟线程

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

虚拟线程的一些优点:

  • 提高应用程序吞吐量

  • 提高应用程序可用性

  • 减少内存消耗

示例代码:

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

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

        for (int i = 0; i < 10; i++) {
            int taskId = i;
            executor.execute(() -> {
                System.out.println("Task " + taskId + " is running on virtual thread: " + Thread.currentThread().getName());
            });
        }
        try {
            Thread.sleep(2000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        executor.shutdown();
    }

}
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐