当前位置:   article > 正文

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

jdk17

目录

前言

一、站在开发视角,从 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() 方法就会抛出空指针异常.
  1. @Data
  2. public class Student {
  3. private String name;
  4. private Integer age;
  5. }

1)创建 Optional 对象案例

  • Optional.of(T t):创建一个 Optional 对象,t 必须不为空.
  • Optional.empty():创建一个空的 Optional 实例.
  • Optional.ofNullable(T t):t 可以为 null.
  1. public void test1() {
  2. //创建一个空的 Optional
  3. Optional<Object> empty = Optional.empty();
  4. //创建非空的 Optional
  5. Student student1 = new Student();
  6. Optional<Student> os1 = Optional.of(student1);
  7. //创建一个空的 Optional
  8. Student student2 = null;
  9. Optional<Student> os2 = Optional.of(student2);
  10. }

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

  • boolea isPresent():判断是否包含对象.
  • void ifPresent(Consumer<? super T> consumer): 如果 Optional 中有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它.
  1. public void test2() {
  2. //ifPresent 无参使用: 判断 os1 中是否有值
  3. Student student = new Student();
  4. Optional<Student> os1 = Optional.of(student);
  5. System.out.println(os1.isPresent()); //true
  6. //ifPresent 有参使用: 若 student 对象不为空,则对该对象进行赋值,并打印一句话
  7. os1.ifPresent(aa -> { //此处的 aa 就代指 student
  8. aa.setName("cyk");
  9. aa.setAge(20);
  10. System.out.println("个人信息已初始化: " + student);
  11. });
  12. }

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 接口实现提供的异常.
  1. public void test3() throws Exception {
  2. //get 获取空对象,报错
  3. Student student = null;
  4. Optional<Student> os1 = Optional.ofNullable(student);
  5. Student student1 = os1.get(); //此处抛出异常: java.util.NoSuchElementException: No value present
  6. //如果 student 为空,就返回一个新对象
  7. Student student2 = os1.orElse(new Student());
  8. //如果 student 为空,就调用我们自己实现的函数
  9. Student student3 = os1.orElseGet(() -> new Student());
  10. //如果 student 为空,就抛出我们指定的异常
  11. os1.orElseThrow(() -> new Exception("自定义异常"));
  12. }

4)过滤

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

5)映射  

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

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

c)使用场景

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

  1. public void test1(Integer id) {
  2. //写法一: 原生
  3. Userinfo userinfo = userinfoMapper.getUserinfoById(id);
  4. if(userinfo != null) {
  5. userinfo.setAge(userinfo.getAge() + 1);
  6. }
  7. //写法二: 使用 Optional 函数式编程,一行搞定
  8. Optional.ofNullable(userinfoMapper.getUserinfoById(id)).ifPresent(p -> p.setAge(p.getAge() + 1));
  9. }

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

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

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

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

1.2、JDK9 新特性

1.2.1、Optional - ifPresentOrElse 解决 if-else

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

  1. Userinfo userinfo = new Userinfo(1, "cyk", 20);
  2. //if-else
  3. if(userinfo != null) {
  4. System.out.println("hello " + userinfo.getUsername());
  5. } else {
  6. System.out.println("world");
  7. }
  8. //ifPresentOrElse
  9. Optional.ofNullable(userinfo)
  10. .ifPresentOrElse(u -> System.out.println("hello " + u.getUsername()),
  11. () -> System.out.println("world"));

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

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

  1. Userinfo nullinfo = null;
  2. //原生
  3. if(nullinfo == null) {
  4. Userinfo userinfo1 = new Userinfo();
  5. userinfo1.setId(1);
  6. if(userinfo1 == null) {
  7. Userinfo userinfo2 = new Userinfo();
  8. userinfo2.setId(2);
  9. return userinfo2;
  10. }
  11. return userinfo1;
  12. }
  13. //Optional 改进后
  14. Optional<Userinfo> or = Optional.ofNullable(nullinfo)
  15. .or(() -> { // nullinfo 为 null,因此执行此 or
  16. Userinfo userinfo1 = new Userinfo();
  17. userinfo1.setId(1);
  18. return Optional.ofNullable(null); //返回一个空的 Optional
  19. })
  20. .or(() -> { // 上一个 or 返回的 Optional 中没有值时,执行此 or
  21. Userinfo userinfo2 = new Userinfo();
  22. userinfo2.setId(2);
  23. return Optional.ofNullable(userinfo2);
  24. });
  25. 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. //1.创建不可变的 List
  2. List<String> strList = List.of("aaa", "bbb", "ccc");
  3. //strList.add("ddd"); //报错: Exception in thread "main" java.lang.UnsupportedOperationException
  4. //2.创建一个不可变的 set/map
  5. Set<String> set = Set.of("aaa", "bbb", "ccc");
  6. Map<String, String> map1 = Map.of("1", "aaa", "2", "bbb", "3", "ccc");
  7. //以上 map 创建方式可能会导致分不清 key value,因此也可以通过以下方式创建
  8. Map<String, String> map2 = Map.ofEntries(Map.entry("1", "bbb"), Map.entry("2", "bbb"));
  9. //set/map 不能保证输出的顺序和定义 键值对 的顺序一致
  10. System.out.println(map1);

1.2.5、集合增强 - takeWhile 方法

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

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

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

1.2.6、集合增强 - dropWhile 方法

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

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

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

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

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

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

1.3、JDK10

1.3.1、copyOf 方法

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

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

  1. List<String> srcList = new ArrayList<>();
  2. srcList.add("aaa");
  3. srcList.add("bbb");
  4. List<String> copyList = List.copyOf(srcList);
  5. srcList.add("ccc");
  6. System.out.println(srcList); //[aaa, bbb, ccc]
  7. System.out.println(copyList);//[aaa, bbb]

1.4、JDK14 新特性

1.4.1、支持文本块

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

  1. //原始
  2. String before = "{\n" +
  3. " \"name\":\"cyk\",\n" +
  4. " \"age\": 20;\n" +
  5. "}";
  6. //增强
  7. String after = """
  8. {
  9. "name": "cyk",
  10. "age": 20
  11. }
  12. """;

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

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

  1. //Before:
  2. Exception in thread "main" java.lang.NullPointerException
  3. at com.dev.wizard.feature.JDK17Demo.optionalMethod_orElseThrow(JDK17Demo.java:99)
  4. at com.dev.wizard.feature.JDK17Demo.main(JDK17Demo.java:23)
  5. //After:
  6. Exception in thread "main" java.lang.NullPointerException: Cannot read field "student" because "persons" is null
  7. at com.dev.wizard.feature.JDK17Demo.optionalMethod_orElseThrow(JDK17Demo.java:99)
  8. at com.dev.wizard.feature.JDK17Demo.main(JDK17Demo.java:23)

1.4.3、instanceof 类型转换

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

  1. Object val = "aaa";
  2. //before
  3. if(val instanceof String) {
  4. String newVal = (String) val;
  5. System.out.println(newVal);
  6. }
  7. //after
  8. if(val instanceof String newVal) {
  9. System.out.println(newVal);
  10. }

1.5、JDK16 新特性

1.5.1、toList 方法

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

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

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

1.6、JDK17 新特性

1.6.2、switch 增强

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

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

1)字符串匹配

  1. //1.字符串匹配
  2. String val1 = "aaa";
  3. //before
  4. switch (val1) {
  5. case "abc":
  6. System.out.println("abc!");
  7. break;
  8. case "aaa":
  9. System.out.println("aaa!");
  10. break;
  11. default:
  12. System.out.println("error!");
  13. }
  14. //after
  15. switch (val1) {
  16. case "abc" -> System.out.println("abc!");
  17. case "aaa" -> System.out.println("aaa");
  18. default -> System.out.println("error");
  19. }

2)类型判断

  1. //2.类型判断
  2. Object val2 = "aaa";
  3. //before
  4. if(val2 instanceof String) {
  5. String newVal = (String) val2;
  6. System.out.println("String:" + newVal);
  7. } else if(val2 instanceof Integer) {
  8. Integer newVal = (Integer) val2;
  9. System.out.println("Integer:" + newVal);
  10. } else {
  11. System.out.println(val2);
  12. }
  13. //after
  14. switch (val2) {
  15. case String str -> {
  16. String newVal = str;
  17. System.out.println("String:" + newVal);
  18. }
  19. case Integer num -> {
  20. Integer newVal = num;
  21. System.out.println("Integer:" + newVal);
  22. }
  23. default -> System.out.println(val2);
  24. }

 3)对 null 的处理

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

4)对条件判断的处理

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/727428
推荐阅读
相关标签
  

闽ICP备14008679号