JDK17 - 开发者视角,从 JDK8 ~ JDK17 都增加了哪些新特性

news2024/11/20 6:23:59

目录

前言

一、站在开发视角,从 JDK8 升级到 JDK17 都有哪些新特性

1.1、JDK8 新特性

1.1.1、Optional 类

a)简介

b)使用方法

c)使用场景

1.2、JDK9 新特性

1.2.1、Optional - ifPresentOrElse 解决 if-else

1.2.2、Optional - or 解决多重 if 嵌套

1.2.3、Optional - orElseThrow 内置异常

1.2.4、集合增强 - 集合静态工厂

1.2.5、集合增强 - takeWhile 方法

1.2.6、集合增强 - dropWhile 方法

1.2.7、接口可以定义私有方法

1.3、JDK10

1.3.1、copyOf 方法

1.4、JDK14 新特性

1.4.1、支持文本块

1.4.2、空指针异常的精确定位

1.4.3、instanceof 类型转换

1.5、JDK16 新特性

1.5.1、toList 方法

1.6、JDK17 新特性

1.6.2、switch 增强


前言


本文只是站在开发者视角,来看看升级哪些咱们程序员常用的功能~

一、站在开发视角,从 JDK8 升级到 JDK17 都有哪些新特性


1.1、JDK8 新特性

1.1.1、Optional 类

a)简介

经过统计,空指针异常是导致 Java 应用程序失败的最常见原因,因此 Google 公司 引入了 Optional 类以检查空值的方式来避免空指针异常,使程序员写出更干净的代码.

Optional 类(Java.util.Optional)是一个容器类,可以保存类型T值,表示这个值存在。或者,也可以只保存 null,表示这个值不存在。也就是说,以前用 null 表示一个值不存在,现在 Optional 就可以更好的表达这个概念,避免空指针异常.

b)使用方法

Java文档中说明:这是一个可以为 null 的容器对象.

  • 如果值存在,则 isPresent() 方法会返回 true,调用 get() 方法就会返回该对象.
  • 如果值不存在,则 isPresent() 方法会返回 false,调用 get() 方法就会抛出空指针异常.
@Data
public class Student {

    private String name;
    private Integer age;

}

1)创建 Optional 对象案例

  • Optional.of(T t):创建一个 Optional 对象,t 必须不为空.
  • Optional.empty():创建一个空的 Optional 实例.
  • Optional.ofNullable(T t):t 可以为 null.
    public void test1() {
        //创建一个空的 Optional
        Optional<Object> empty = Optional.empty();

        //创建非空的 Optional
        Student student1 = new Student();
        Optional<Student> os1 = Optional.of(student1);

        //创建一个空的 Optional
        Student student2 = null;
        Optional<Student> os2 = Optional.of(student2);
    }

2)判断 Optional 容器中是否包含对象

  • boolea isPresent():判断是否包含对象.
  • void ifPresent(Consumer<? super T> consumer): 如果 Optional 中有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它.
    public void test2() {
        //ifPresent 无参使用: 判断 os1 中是否有值
        Student student = new Student();
        Optional<Student> os1 = Optional.of(student);
        System.out.println(os1.isPresent()); //true

        //ifPresent 有参使用: 若 student 对象不为空,则对该对象进行赋值,并打印一句话
        os1.ifPresent(aa -> { //此处的 aa 就代指 student
            aa.setName("cyk");
            aa.setAge(20);
            System.out.println("个人信息已初始化: " + student);
        });
    }

3)获取 Optional 容器的对象

  • T get():如果 Optional 包含值,则返回值,否则抛出异常.
  • T orElse(T other):如果 Optional 包含值就返回,否则返回指定的 other 对象.
  • T orElseGet(Supplier<? extends T> other):如果 Optional 包含值就返回,否则返回由Supplier接口实现提供的对象.
  • T orElseThrow(Supplier<? extends X> exceptionSupplier):如果 Optional 包含值则将其返回,否则抛出由 Supplier 接口实现提供的异常.
    public void test3() throws Exception {
        //get 获取空对象,报错
        Student student = null;
        Optional<Student> os1 = Optional.ofNullable(student);
        Student student1 = os1.get(); //此处抛出异常: java.util.NoSuchElementException: No value present

        //如果 student 为空,就返回一个新对象
        Student student2 = os1.orElse(new Student());

        //如果 student 为空,就调用我们自己实现的函数
        Student student3 = os1.orElseGet(() -> new Student());

        //如果 student 为空,就抛出我们指定的异常
        os1.orElseThrow(() -> new Exception("自定义异常"));
    }

4)过滤

  • Optional<T> filter(Predicate<? super <T> predicate):如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。
    public void test4() {
        Student student = new Student("cyk", 20);
        Optional<Student> os1 = Optional.ofNullable(student);
        os1.filter(aa -> aa.getName().equals("cyk")) //此处 aa 代指 student
                .ifPresent(result -> System.out.println("ok!"));
    }

5)映射  

map:入参就是 Optional 中的值,并且具有返回值(返回类型就是Optional 对象中的值类型),如果值才执行函数体,否则返回空的 Optional.

    public void test5() {
        Student student = new Student("cyk", 20);
        Optional<Student> os1 = Optional.ofNullable(student);
        //如果 os1 中存在值,就执行 lambda 表达式,如果不存在值,就返回一个空的 Optional
        Optional<Student> result = os1.map(aa -> {
            aa.setAge(aa.getAge() + 1);
            return aa;
        });
        System.out.println(result); //输出: Optional[Student(name=cyk, age=21)]
    }

c)使用场景

1)例如当你根据 id 从数据库中获取到用户数据时,如果用户数据不为 null,才能可以将年龄 +1.

    public void test1(Integer id) {
        //写法一: 原生
        Userinfo userinfo = userinfoMapper.getUserinfoById(id);
        if(userinfo != null) {
            userinfo.setAge(userinfo.getAge() + 1);
        }

        //写法二: 使用 Optional 函数式编程,一行搞定
        Optional.ofNullable(userinfoMapper.getUserinfoById(id)).ifPresent(p -> p.setAge(p.getAge() + 1));
    }

2)当传入的用户数据需要进行判空抛异常处理时

    public void test2() {
        Userinfo userinfo = new Userinfo(1, null, 20);
        //原生
        if(userinfo == null || isEmpty(userinfo.getUsername())
                || isEmpty(userinfo.getAge())) {
            throw new RuntimeException("用户数据不能为空!");
        }
        //用 Optional 改进
        Optional.ofNullable(userinfo)
                .filter(p -> isEmpty(p.getUsername()) || isEmpty(p.getAge()))
                .orElseThrow(() -> new RuntimeException("用户数据不能为空"));
    }

3)对象赋值,如果有值,则执行业务逻辑,如果没有值,则返回一个默认的对象.

        Optional.ofNullable(userinfo)
                .map(u -> {
                    //业务逻辑...
                    u.setId(2);
                    u.setUsername("cyk");
                    u.setAge(20);
                    return u;
                })
                .orElse(new Userinfo(100, "xxx", 0));

1.2、JDK9 新特性

1.2.1、Optional - ifPresentOrElse 解决 if-else

为了解决 if-else 的判断判空情况,JDK9 增强了 Optional,提供了 ifPresentOrElse.

        Userinfo userinfo = new Userinfo(1, "cyk", 20);
        //if-else
        if(userinfo != null) {
            System.out.println("hello " + userinfo.getUsername());
        } else {
            System.out.println("world");
        }
        //ifPresentOrElse
        Optional.ofNullable(userinfo)
                .ifPresentOrElse(u -> System.out.println("hello " + u.getUsername()),
                        () -> System.out.println("world"));

1.2.2、Optional - or 解决多重 if 嵌套

多重 if 容易导致代码可读性降低,误判引发空指针,并且对于多种if嵌套的情况我还是建议大家提前 return(逻辑更清晰),因此 JDK9 增强 Optional ,提供了 or 方法.

        Userinfo nullinfo = null;
        //原生
        if(nullinfo == null) {
            Userinfo userinfo1 = new Userinfo();
            userinfo1.setId(1);
            if(userinfo1 == null) {
                Userinfo userinfo2 = new Userinfo();
                userinfo2.setId(2);
                return userinfo2;
            }
            return userinfo1;
        }
        //Optional 改进后
        Optional<Userinfo> or = Optional.ofNullable(nullinfo)
                .or(() -> { // nullinfo 为 null,因此执行此 or
                    Userinfo userinfo1 = new Userinfo();
                    userinfo1.setId(1);
                    return Optional.ofNullable(null); //返回一个空的 Optional
                })
                .or(() -> { // 上一个 or 返回的 Optional 中没有值时,执行此 or
                    Userinfo userinfo2 = new Userinfo();
                    userinfo2.setId(2);
                    return Optional.ofNullable(userinfo2);
                });
        System.out.println(or); //输出: Optional[Userinfo(id=2, username=null, age=null)]

1.2.3、Optional - orElseThrow 内置异常

Optional.ofNullable(null).orElseThrow();

该方法会抛出Optional的内置异常NoSuchElementException.

1.2.4、集合增强 - 集合静态工厂

  • 此方式创建的集合对象都不允许任何写操作,并且都不能为 null.
  • set/map 不能保证输出顺序和定义的顺序一致.
  • 与 Arrays.asList 创建的 List 不同,Arrays 创建的 List 可以 update不能 add/remove ,而静态工厂创建的完全不能进行写操作.
        //1.创建不可变的 List
        List<String> strList = List.of("aaa", "bbb", "ccc");
        //strList.add("ddd"); //报错: Exception in thread "main" java.lang.UnsupportedOperationException

        //2.创建一个不可变的 set/map
        Set<String> set = Set.of("aaa", "bbb", "ccc");
        Map<String, String> map1 = Map.of("1", "aaa", "2", "bbb", "3", "ccc");
        //以上 map 创建方式可能会导致分不清 key value,因此也可以通过以下方式创建
        Map<String, String> map2 = Map.ofEntries(Map.entry("1", "bbb"), Map.entry("2", "bbb"));
        //set/map 不能保证输出的顺序和定义 键值对 的顺序一致
        System.out.println(map1);

1.2.5、集合增强 - takeWhile 方法

takeWhile 用来从前向后遍历,遇到不满足的就结束流,最后返回从前到不满足的截断结果(流对象).

        List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7);
        List<Integer> result = list.stream().takeWhile(val -> val < 5).toList();
        System.out.println(result); //输出: [1, 2, 3, 4]

Ps:如果使用不可修改的Set或者Map 在使用这个方法是要注意 会存在每次输出的结果都是不一样的

1.2.6、集合增强 - dropWhile 方法

takeWhile 用来从前向后删除,遇到不满足的就结束流,最后返回原始流剩下的结果(流对象).

因此,也可以理解为 takeWhile 的补集.

        List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7);
        List<Integer> result = list.stream().dropWhile(val -> val < 5).toList();
        System.out.println(result); //输出: [5, 6, 7]
        System.out.println(list); //Ps: 这里的删除,不影响 list 中原本的值

Ps:如果使用不可修改的Set或者Map 在使用这个方法和takeWhile一样是要注意;

1.2.7、接口可以定义私有方法

接口可以定义一些私有的方法给 default 方法调用,仅此而已。

1.3、JDK10

1.3.1、copyOf 方法

集合提供了 copyOf 方法,返回的不可以修改的集合(修改就抛异常).

Ps:这里使用的深拷贝,因此修改原集合不会影响副本.

        List<String> srcList = new ArrayList<>();
        srcList.add("aaa");
        srcList.add("bbb");
        List<String> copyList = List.copyOf(srcList);
        srcList.add("ccc");
        System.out.println(srcList); //[aaa, bbb, ccc]
        System.out.println(copyList);//[aaa, bbb]

1.4、JDK14 新特性

1.4.1、支持文本块

文本代码块让整个String看上去都是比较整洁的,并且无需进行繁琐的转义.

        //原始
        String before = "{\n" +
                        "     \"name\":\"cyk\",\n" +
                        "     \"age\": 20;\n" +
                        "}";
        //增强
        String after = """
                      {
                          "name": "cyk",
                          "age": 20
                      }
                      """;

1.4.2、空指针异常的精确定位

不光可以定义是哪行代码空指针异常,还能定位到调用到哪个方法/属性出现的异常.

//Before:

Exception in thread "main" java.lang.NullPointerException
 at com.dev.wizard.feature.JDK17Demo.optionalMethod_orElseThrow(JDK17Demo.java:99)
 at com.dev.wizard.feature.JDK17Demo.main(JDK17Demo.java:23)

//After:

Exception in thread "main" java.lang.NullPointerException: Cannot read field "student" because "persons" is null
 at com.dev.wizard.feature.JDK17Demo.optionalMethod_orElseThrow(JDK17Demo.java:99)
 at com.dev.wizard.feature.JDK17Demo.main(JDK17Demo.java:23)

1.4.3、instanceof 类型转换

以往 instanceof 只能帮我们检查数据类型是否符合,JDK14 中不仅可以进行类型匹配,还会将匹配到的类型直接赋值新的引用,简化了开发,提高了可读性.

        Object val = "aaa";

        //before
        if(val instanceof String) {
            String newVal = (String) val;
            System.out.println(newVal);
        }
        //after
        if(val instanceof String newVal) {
            System.out.println(newVal);
        }

1.5、JDK16 新特性

1.5.1、toList 方法

stream().toList 和 Collectors.toUnmodifiableList()都是不可修改的集合,Collectors.toList()是生成的是普通的list,可写。

性能比较:toList(优) --> Collectors.toList() --> Collectors.toUnmodifiableList(劣)

        List<String> list1 = List.of("aaa", "bbb");
        //可读可写
        List<String> list2 = list1.stream().toList();
        //可读,不可写
        List<String> list3 = list2.stream().collect(Collectors.toList());
        List<String> list4 = list1.stream().collect(Collectors.toUnmodifiableList());

1.6、JDK17 新特性

1.6.2、switch 增强

JDK17 中的 switch 主要是使用 -> 替代了 break 语句,看上去更加简洁.

看上去 switch 是想替代 if-else 的感觉~

1)字符串匹配

        //1.字符串匹配
        String val1 = "aaa";

        //before
        switch (val1) {
            case "abc":
                System.out.println("abc!");
                break;
            case "aaa":
                System.out.println("aaa!");
                break;
            default:
                System.out.println("error!");
        }
        //after
        switch (val1) {
            case "abc" -> System.out.println("abc!");
            case "aaa" -> System.out.println("aaa");
            default -> System.out.println("error");
        }

2)类型判断

        //2.类型判断
        Object val2 = "aaa";

        //before
        if(val2 instanceof String) {
            String newVal = (String) val2;
            System.out.println("String:" + newVal);
        } else if(val2 instanceof Integer) {
            Integer newVal = (Integer) val2;
            System.out.println("Integer:" + newVal);
        } else {
            System.out.println(val2);
        }

        //after
        switch (val2) {
            case String str -> {
                String newVal = str;
                System.out.println("String:" + newVal);
            }
            case Integer num -> {
                Integer newVal = num;
                System.out.println("Integer:" + newVal);
            }
            default -> System.out.println(val2);
        }

 3)对 null 的处理

        //3.对 null 的处理
        String val3 = null;
        switch (val3) {
            case null -> System.out.println("null!");
            case "aaa" -> System.out.println("aaa!");
            case "bbb" -> System.out.println("bbb!");
            default -> System.out.println("error");
        }

4)对条件判断的处理

        //4.对条件判断的处理
        Object obj = 1;
        switch (obj) {
            case String str -> {
                String newVal = str;
                System.out.println("String:" + newVal);
            }
            case Integer num && num < 3 -> {
                Integer newVal = num;
                System.out.println("Integer:" + newVal);
            }
            default -> System.out.println("error!");
        }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1351448.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

每天刷两道题——第三天

1.1两两交换链表中的节点 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09; 输入&#xff1a;[1,2,3,4] 输出&#xff1a;[2,1,4,3…

【ESP-NOW Web 服务器传感器仪表板 (ESP-NOW + Wi-Fi)】

【ESP-NOW Web 服务器传感器仪表板 &#xff08;ESP-NOW Wi-Fi&#xff09;】 1. 前言2. 同时使用 ESP-NOW 和 Wi-Fi3. 项目概况4. 先决条件4.1 环境配置4.2 DHT 库4.3 ESPAsyncWebSrv服务器库4.4 Arduino_JSON4.5 所需零件4.6 获取接收板 MAC 地址4.7 ESP32 发送电路 5. ESP3…

常见安全概念澄清,Java小白入门(八)

认证 认证 (Identification) 是验证当前用户的身份。 常见的认证技术&#xff1a; 身份证用户名和密码用户手机&#xff1a;手机短信、手机二维码扫描、手势密码用户的电子邮箱用户的生物学特征&#xff1a;指纹、语音、眼睛虹膜 授权 授权 (Authorization) 指赋予用户系统…

js常用事件演示

目录 JS事件的具体方法 窗口事件 表单事件 键盘事件 鼠标事件 知识小拓展 JS事件的具体方法 我们用到JavaScript的时候js的事件就显得特别重要了 事件名说明onsubmit当表单提交时触发该事件onclick鼠标单击事件ondblclick鼠标双击事件onblur元素失去焦点onfocus元素获得…

了解深度学习优化器:Momentum、AdaGrad、RMSProp 和 Adam

slavahead 一、介绍 DEEP学习在人工智能领域迈出了一大步。目前&#xff0c;神经网络在非表格数据&#xff08;图像、视频、音频等&#xff09;上的表现优于其他类型的算法。深度学习模型通常具有很强的复杂性&#xff0c;并提出数百万甚至数十亿个可训练的参数。这就是为什么在…

玩转贝启科技BQ3588C开源鸿蒙系统开发板 —— 编译构建及此过程中的踩坑填坑(1)

接前一篇文章&#xff1a;玩转贝启科技BQ3588C开源鸿蒙系统开发板 —— 代码下载&#xff08;2&#xff09; 本文主要参考&#xff1a; BQ3588C_代码下载 上一回完成了代码下载&#xff0c;本回开始进行编译构建。 1. 编译构建 &#xff08;1&#xff09;执行prebuilts 在源…

SpringBoot 集成支付宝支付

网页操作步骤 1.进入支付宝开发平台—沙箱环境 使用开发者账号登录开放平台控制平台 2.点击沙箱进入沙箱环境 说明&#xff1a;沙箱环境支持的产品&#xff0c;可以在沙箱控制台 沙箱应用 > 产品列表 中查看。 3.进入沙箱&#xff0c;配置接口加签方式 在沙箱进行调试前…

扫地机器人地图与用户终端的同步

以下内容为本人的学习笔记&#xff0c;如需要转载&#xff0c;请声明原文链接 微信公众号「ENG八戒」https://mp.weixin.qq.com/s/APaJheSbgTW3jNssWsp5Ng 地图数据来源于机器人算法模块&#xff0c;一般通过SLAM算法完成建图的过程。 建图过程中&#xff0c;基础数据涉及到各…

Android 串口协议

前言 本协议是 Android 应用端与主控板之间的通信协议&#xff0c;是串行通信协议。 协议要求同一时间只能有两个通讯端点在相互通讯&#xff0c;采用小端传输数据。 硬件层基于RS485协议&#xff0c;采取半双工&#xff0c;一主多从的通讯模式。Android定义为主机&#xff0c…

一、初识Redis与分布式系统

目录 一、Redis应用 二、实现方式 三、Redis应用 四、分布式系统 五、分布式系统实现 1、应用服务和数据库服务分离 2、引入负载均衡&#xff0c;应用服务器集群&#xff08;解决高并发&#xff09; 3、引入读写分离&#xff0c;数据库主从结构&#xff08;解决高并发&a…

如何在iPhone设备中查看崩溃日志

​ 目录 如何在iPhone设备中查看崩溃日志 摘要 引言 导致iPhone设备崩溃的主要原因是什么&#xff1f; 使用克魔助手查看iPhone设备中的崩溃日志 奔溃日志分析 总结 摘要 本文介绍了如何在iPhone设备中查看崩溃日志&#xff0c;以便调查崩溃的原因。我们将展示三种不同的…

流媒体学习之路(WebRTC)——GCC分析(4)

流媒体学习之路(WebRTC)——GCC分析&#xff08;4&#xff09; —— 我正在的github给大家开发一个用于做实验的项目 —— github.com/qw225967/Bifrost目标&#xff1a;可以让大家熟悉各类Qos能力、带宽估计能力&#xff0c;提供每个环节关键参数调节接口并实现一个json全配置…

【Java并发】深入浅出 synchronized关键词原理-上

一个问题的思考 建设我们有两个线程&#xff0c;一个进行5000次的相加操作&#xff0c;另一个进行5000次的减操作。那么最终结果是多少 package com.jia.syn;import java.util.concurrent.TimeUnit;/*** author qxlx* date 2024/1/2 10:08 PM*/ public class SynTest {privat…

使用Vue3开发学生管理系统模板1

环境搭建 通过解压之前《Vue3开发后台管理系统模板》的代码&#xff0c;我们能够得到用户增删改查的页面&#xff0c;我们基于用户增删改查的页面做进一步的优化。 创建学生增删改查页面 第一步&#xff1a;复制用户增删改查页面&#xff0c;重命名为StudentCRUD.vue <…

新闻稿发布:媒体重要还是价格重要

在当今信息爆炸的数字时代&#xff0c;企业推广与品牌塑造不可或缺的一环就是新闻稿发布。新闻稿是一种通过媒体渠道传递企业信息、宣传品牌、事件或产品新闻的文本形式。发布新闻稿的过程旨在将企业的声音传递给更广泛的受众&#xff0c;借助媒体平台实现品牌故事的广泛传播。…

exec、execFile、fork、spawn的区别与使用场景

在Node.js中&#xff0c;通过子进程可以实现并行执行任务&#xff0c;处理复杂的操作&#xff0c;以及与外部命令或文件进行交互。Node.js提供了多种子进程创建方法&#xff0c;包括exec、execFile、fork和spawn。本文将对这些方法进行比较&#xff0c;并介绍它们的适用场景和示…

【深度学习-基础学习】Transformer 笔记

本篇文章学习总结 李宏毅 2021 Spring 课程中关于 Transformer 相关的内容。课程链接以及PPT&#xff1a;李宏毅Spring2021ML这篇Blog需要Self-Attention为前置知识。 Transfomer 简介 Transfomer 架构主要是用来解决 Seq2Seq 问题的&#xff0c;也就是 Sequence to Sequence…

大数据StarRocks(一) StarRocks概述

1 StarRocks介绍 StarRocks是新一代极速全场景MPP(Massively Parallel Processing)数据库&#xff0c;它充分吸收关系型OLAP数据库和分布式存储系统在大数据时代的优秀研究成果&#xff0c;在业界实践的基础上&#xff0c;进一步改进优化、升级架构&#xff0c;并增添了众多全…

NSSCTF 1zjs

开启环境: 搞就完事了,别玩魔法! 源码打开 点击访问:./dist/index.umd.js" 搜索php,找到23条相关的,注意到有一个特别的信息: PERFORMANCE OF THIS SOFTWARE.Your gift just take it : /fk3f1ag.php 访问: node4.anna.nssctf.cn:28325/fk3f1ag.php 得到这样: ([![]…

【hyperledger-fabric】部署和安装

简介 对hyperledger-fabric进行安装&#xff0c;话不多说&#xff0c;直接开干。但是需要申明一点&#xff0c;也就是本文章全程是开着加速器进行的资源操作&#xff0c;所以对于没有开加速器的情况可能会由于网络原因导致下载资源失败。 资料提供 1.官方部署文档在此&#…