简单整理一下JDK9-JDK17在开发中可能常用到的一些新功能

简单梳理一下从 JDK9JDK17 这些版本在 CRUD 中可能常用到的一些新功能;

毕竟现在 Sping6、SpringBoot3 都已经要求是 JDK17

虽然现在用的还是 JDK8... 但是新版本增加了哪些新功能还是要了解一下的

平常都是大致浏览一下看看哪个版本有啥新功能,现在印象中只记得新增了记录类、密封类,还有 var ,但其实还有很多其它有用的功能,比如 JDK14 中的空指针异常,详情更加的清晰明了

如果你用的是 JDK17 ,那么下面列举的新功能都能使用

建议使用 JDK17,因为 JDK17 是一个长期支持的版本

本文只是简单梳理记录并简单演示一下怎么使用

JDK9

1. 模块化
2. 使用 of 创建不可变集合
 

ini

复制代码

List<Integer> list = List.of(1, 2, 3, 4, 5); Map<String, Integer> map = Map.of("key1", 1, "key2", 2, "key3", 3);

3. stream api 新增了4个流操作方法
  1. dropWhile

    从开头开始删除满足条件的元素,直到遇到第一个不满足条件的,然后返回剩余的元素

     ini 

    复制代码

    List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); List<Integer> result = numbers.stream()                       .dropWhile(n -> n < 5)                       .collect(Collectors.toList()); System.out.println(result); // 输出:[5, 6, 7, 8, 9, 10]
  2. takeWhile

    从开头开始获取满足条件的元素,直到遇到第一个不满足条件的,然后返回前面满足条件的元素

     ini 

    复制代码

    List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); List<Integer> result = numbers.stream()                       .takeWhile(n -> n < 5)                       .collect(Collectors.toList()); System.out.println(result); // 输出:[1, 2, 3, 4]
  3. ofNullable,可接受 null

     ini 

    复制代码

    String name = "Hello World"; Stream<String> stream = Stream.ofNullable(name); // 输出:Hello World stream.forEach(System.out::println); name = null; stream = Stream.ofNullable(name); // 无输出 stream.forEach(System.out::println);
  4. iterate

    传入一个种子值和一个生成函数,根据生成函数生成一个无限流。

    文字有点太抽象,直接看代码吧

     arduino 

    复制代码

    public static void main(String[] args) { // 初始值从1开始,每次将前一个数乘以2 Stream.iterate(1, n -> n * 2) .limit(10) .forEach(System.out::println); // 也可以添加判断条件,当n大于10时停止 Stream.iterate(1, n -> n <= 10, n -> n + 1) .forEach(System.out::println); // 生成自定义对象 Stream.iterate(new Person("John Wick", 30), person -> new Person(person.getName(), person.getAge() + 1)) .limit(10) .forEach(System.out::println); // 生成斐波那契数列 Stream.iterate(new int[]{0, 1}, arr -> new int[]{arr[1], arr[0] + arr[1]}) .mapToInt(arr -> arr[0]) .limit(10) .forEach(System.out::println); // 生成无限序列的日期 Stream.iterate(LocalDate.now(), date -> date.plusDays(1)) .limit(10) .forEach(System.out::println); }

    自己可以复制代码运行看看......

4. 私有接口方法(Private Interface Methods)

私有方法作用范围限制在类或接口内部,外部类无法访问和重写

有什么用呢?比如可以将一些通用功能封装到私有方法中,每个实现类不用重复的去重写该方法。

下面是一个简单示例

 

csharp

复制代码

public interface Calculator { int add(int a, int b); int subtract(int a, int b); int multiply(int a, int b); int divide(int a, int b); /** * 默认方法 */ default int calculate(int a, int b, String operation) { // 这里用的是switch新语法,不过不是在JDK9 return switch (operation) { case "add" -> validateAndCompute(a, b, this::add); case "subtract" -> validateAndCompute(a, b, this::subtract); case "multiply" -> validateAndCompute(a, b, this::multiply); case "divide" -> validateAndCompute(a, b, this::divide); default -> throw new IllegalArgumentException("Invalid operation: " + operation); }; } /** * 私有方法 */ private int validateAndCompute(int a, int b, BinaryOperator<Integer> operator) { if (a < 0 || b < 0) { throw new IllegalArgumentException("Numbers must be non-negative."); } return operator.apply(a, b); } } public static void main(String[] args) { CalculatorImpl impl = new CalculatorImpl(); int a = -1; int b = 2; int add = impl.calculate(a, b, "add"); System.out.println(add); }

JDK10

1. 局部变量类型推断(语法糖)
 

csharp

复制代码

public class VarExample {    public static void main(String[] args) {        // 推断message为String类型        var message = "Hello, world!";        // 推断number为int类型        var number = 10;        System.out.println(message);        System.out.println(number);        var list = new ArrayList<>();        list.add("Java");        list.add("Python");        list.add("C++"); list.add(1);        for (var item : list) {            System.out.println(item + ",类型:" + item.getClass());       } // 输出结果 Java,类型:class java.lang.String Python,类型:class java.lang.String C++,类型:class java.lang.String 1,类型:class java.lang.Integer   } }

2. streamcollectors 可指定为不可变的集合
 

scss

复制代码

// 以前的语法 list.stream().collect(Collectors.toList()) // 新增加的 list.stream().collect(Collectors.toUnmodifiableList()); list.stream().collect(Collectors.toUnmodifiableSet()); list.stream().collect(Collectors.toUnmodifiableMap());

JDK11

1. 命令行运行java程序

在命令行下,如果要运行一个 java 类,需要先使用 javac 命令编译类文件,再使用 java 命令运行编译后的文件,这个操作在刚学的时候肯定都做过;

现在在 JDK11 中只需要 java 一个命令就可以了。

 

csharp

复制代码

[root@localhost ~]# java Hello.java

2. 最常用的 string
  1. 空判断

     ini 

    复制代码

    String str = ""; boolean blank = str.isBlank();
  2. 复制

     ini 

    复制代码

    String str = "Hello World;"; // 重复次数2 String repeat = str.repeat(2); // 输出 Hello World;Hello World; System.out.println(repeat);
  3. 将字符串拆分成行

     ini 

    复制代码

    String text = "Hello\nWorld"; // 使用 lines() 方法将字符串拆分成行,并返回一个流 Stream<String> lines = text.lines(); // 此时 lineList 中是两个对象:Hello、World List<String> lineList = lines.collect(Collectors.toList());
  4. 去除字符串前后空格

     ini 

    复制代码

    String str = "   Hello World   ; "; // 输出 Hello World   ; System.out.println(str.strip());
3. 读写文件 File API
 

ini

复制代码

public static void main(String[] args) {    Path filePath = Path.of("C:\Users\Desktop\test.txt");    String content = "Hello World!";    try {        // 写文件 writeString        Files.writeString(filePath, content);        System.out.println("写好了!");   } catch (IOException e) {        e.printStackTrace();   }    try {        // 读文件 readString        String text = Files.readString(filePath);        System.out.println(text);   } catch (IOException e) {        e.printStackTrace();   }        // bytes 写    String content = "Hello, World!"; try {   Files.write(filePath, content.getBytes(StandardCharsets.UTF_8));   System.out.println("写好了!"); } catch (IOException e) {   e.printStackTrace(); }    // bytes 读    try {   byte[] fileBytes = Files.readAllBytes(filePath);   String fileContent = new String(fileBytes, StandardCharsets.UTF_8);   System.out.println(fileContent); } catch (IOException e) {   e.printStackTrace(); } }

4. JDK10 中的 var 局部变量类型推断,在 lambda 表达式中也能用了
 

ini

复制代码

BinaryOperator<Integer> sum = (var a, var b) -> a + b; int result = sum.apply(10, 20); // 输出 30 System.out.println(result);

JDK12

1. switch 表达式,预览版本

优化 switch 表达式语法

2. 文件内容对比 Files.mismatch

返回它们之间第一个不匹配的字符的位置,如果两个文件完全相同,该方法将返回 -1

 

ini

复制代码

String file1 = "file1.txt"; String file2 = "file2.txt"; long mismatch = Files.mismatch(Path.of(file1), Path.of(file2)); System.out.println(mismatch);

JDK13

1. switch新增 yield(预览版本)
2. 文本块,预览版本

JDK14

1. 优化空指针异常打印信息
 

ini

复制代码

public static void main(String[] args) {   String a = "hello";   String b = null;   int len = a.length() + b.length();   System.out.println(len); }

现在空指针异常,在异常信息中会直接告诉你是哪个对象导致的,以前还要自己去排查,这个功能还是非常有用的

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "b" is null

2. switch表达式 ,正式版本(语法糖)
 

ini

复制代码

int day = 2; String dayName = switch (day) {    case 1 -> "星期一";    case 2 -> "星期二";    case 3 -> "星期三";    default -> { // yield 关键字        yield "无效数字";   } }; // 输出 星期三 System.out.println(dayName); int day = 6; String dayType; switch (day) {    case 1, 2, 3, 4, 5 -> dayType = "上班";    case 6, 7 -> dayType = "不上班";    default -> dayType = "无效数字"; } // 输出 不上班 System.out.println(dayType);

JDK15

1. ZGC

没用过应该也都听过了吧,JDK15 中正式发布

 

ruby

复制代码

java -XX:+UseZGC ApplicationName

2. 文本块,正式版本

终于不用各种转义拼接了

 

ini

复制代码

public static void main(String[] args) {    String textBlock = """            Hello,            This is a text block.            It allows you to write            multiple lines of text            without the need for            escape characters or            concatenation operators.            """;    System.out.println(textBlock); }

JDK16

1. instanceof,正式版本
 

typescript

复制代码

Object object = "Hello"; if (object instanceof String s) { System.out.println(s); }

类型匹配对了后,直接就转换为指定类型了,省了一步

2. 记录类 record ,正式版本

详细使用可以看我之前写的文章:JDK16新特性中的record类是什么以及如何使用

3. 密封类 sealed,预览版本

详细使用看下面的 JDK17

JDK17

1. switch 类型匹配,预览版本
 

csharp

复制代码

Object value = 42; // 使用 switch 类型匹配进行处理 switch (value) {    case Integer i -> System.out.println("Integer value: " + i);    case String s -> System.out.println("String value: " + s);    case Double d -> System.out.println("Double value: " + d);    case Long l && l > 0 -> System.out.println("Positive Long value: " + l);    default -> System.out.println("Unknown value"); }

2. 密封类(sealed),正式版本

密封类什么意思呢,就是你想让这个类只能指定的类能继承/实现,其它的类不能继承/实现,对比 final 使用起来更加灵活

 

kotlin

复制代码

public sealed interface Expr permits Add, Multiply { // 使用 permits 指定了只有 Add、Multiply 两个类可以实现该接口 } public final class Add implements Expr { } public final class Multiply implements Expr { }

 

csharp

复制代码

public class Test2 { public static void main(String[] args) { Expr expr1 = new Add(); Expr expr2 = new Multiply(); process(expr1); process(expr2); } private static void process(Expr expr) { switch (expr) { case Add add -> System.out.println("add"); case Multiply multiply -> System.out.println("multiply"); // 这里不需要 default } } }

因为在 Expr 接口类中指定了只有 AddMultiply 这两个类可以实现 Expr接口,所以在 switch 语句最后那里可以不写 default

下面演示一下 recordsealedswitch 的类型匹配,三者的配合使用

  1. 定义一个接口

     csharp 

    复制代码

    public interface Future<V> {    AsyncReturn<V> get(); }
  2. 使用sealed定义一个密封类接口,里面定义 record 类型的实现类

     csharp 

    复制代码

    public sealed interface AsyncReturn<V> {    record Success<V>(V result) implements AsyncReturn<V> {   }    record Failure<V>(Throwable cause) implements AsyncReturn<V> {   }    record Timeout<V>() implements AsyncReturn<V> {   }    record Interrupted<V>() implements AsyncReturn<V> {   } }
  3. 使用

     arduino 

    复制代码

    public static void main(String[] args) {    // 创建一个线程池    ExecutorService executor = Executors.newSingleThreadExecutor();    Future<String> future = () -> {        // 在这里执行异步操作,并返回相应的AsyncReturn实例        try {            // 模拟异步操作,这里使用线程池提交一个任务            java.util.concurrent.Future<String> asyncResult = executor.submit(() -> {                // 模拟耗时操作                Thread.sleep(2000);                return "Hello World!";           });            // 获取异步操作结果,阻塞等待结果            String result = asyncResult.get();            // 返回异步操作成功的结果            return new AsyncReturn.Success<>(result);       } catch (Exception e) {            // 返回异步操作失败的原因            return new AsyncReturn.Failure<>(e);       }   };    // 调用Future的get()方法获取异步操作的结果    AsyncReturn<String> asyncResult = future.get();    // 使用 switch 类型匹配进行处理    switch (asyncResult) {        case AsyncReturn.Success<String> successResult -> {            String result = successResult.result();            System.out.println("异步操作成功: " + result);       }        case AsyncReturn.Failure<String> failureResult -> {            Throwable cause = failureResult.cause();            System.out.println("异步操作失败: " + cause.getMessage());       }        case AsyncReturn.Timeout<String> timeoutResult -> System.out.println("超时");        case AsyncReturn.Interrupted<String> interruptedResult -> System.out.println("中断");   }    // 关闭线程池    executor.shutdown(); }

大致就这些吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值