聊一聊Java8 Optional,让你的代码更加优雅

简介: 随着时间的推移,曾经我们觉得重要的东西,可能在今天看来是如此的浅薄和无知,同理,今天我们放不下,想不开,觉得重要的东西,多年后我们可能也会觉得也就那样,所以,今天的的所有烦恼,忧愁,想不开,其实我们都没必要过于在意,因为有些东西随着时间的冲刷,也就那样了。

码农在囧途


随着时间的推移,曾经我们觉得重要的东西,可能在今天看来是如此的浅薄和无知,同理,今天我们放不下,想不开,觉得重要的东西,多年后我们可能也会觉得也就那样,所以,今天的的所有烦恼,忧愁,想不开,其实我们都没必要过于在意,因为有些东西随着时间的冲刷,也就那样了。


前言


Java8提供了Optional接口,Optional接口能够是我们的代码变得更加的优雅,可读性更高,同时能够很好的避免空指针,因为空指针是一个很让人头疼的问题,特别对于调用第三方接口,如果不知道对象的规约的时候,我们在取值的时候无法直到那些值能为空,那些不能为空,所以容易出现空指针,如果我们谨慎一点,可能会对每一个值进行判空处理,但是将会充斥着大量的if语句,甚是不雅观。


下面我们介绍一下Optional类的方法


empty()


返回一个空的Optional对象 Optional.empty


of(T value)


参数传入一个对象,返回一个Option对象,value不能为空,如果为null,将抛出空指针异常


 /**
  * @author 刘牌
  * @date 2022-03-2921:52
  */
 public class OptionalTest {
     public static void main(String[] args) {
         User user = null;
         Optional<User> optional = Optional.of(user);
         System.out.println(user);
     }
 }


ofNullable(T value)


参数传入一个对象,可以为空,如果为空,将返回一个空的Optional对象,就等于Optional.empty(),输出的值为Optional.empty,如果不为空,返回一个不为空的Optional对象


 /**
  * @author 刘牌
  * @date 2022-03-2921:52
  */
 public class OptionalTest {
     public static void main(String[] args) {
         User user = null;
         Optional<User> optional = Optional.ofNullable(user);
         System.out.println(optional);
     }
 }


get()


获取Optional中的值,这个值也就是我们的值,Optional相当于就是一个外壳。


 public class OptionalTest {
     public static void main(String[] args) {
         User user = null;
         Optional<User> optional = Optional.ofNullable(user);
         User user1 = optional.get();
     }
 }


isPresent()


判断Optional对象中是否有值,如果有值,返回true,没值返回false。


true


 public class OptionalTest {
     public static void main(String[] args) {
         User user = new User();
         Optional<User> optional = Optional.ofNullable(user);
         System.out.println(optional.isPresent());
     }
 }


false


 public class OptionalTest {
     public static void main(String[] args) {
         User user = null;
         Optional<User> optional = Optional.ofNullable(user);
         System.out.println(optional.isPresent());
     }
 }


ifPresent(Consumer<? super T> consumer)


ifPresent参数是一个函数式接口,无返回值,会将Optional中的值作为参数传递到ifPresent()中


 public class OptionalTest {
     public static void main(String[] args) {
         User user = new User();
         Optional<User> optional = Optional.ofNullable(user);
         optional.ifPresent(s -> System.out.println(s));
     }
 }


filter(Predicate<? super T> predicate)


是一个Predicate函数接口,会将Optional中的值作为参数传入,如果符合规则,那么返回一个Optional对象,否则返回一个空的Optional 对象(Optional.empty) 符合规则,返回Optional对象


 public class OptionalTest {
     public static void main(String[] args) {
         User user = new User();
         user.setUsername("我是小四哥");
         Optional<User> optional = Optional.ofNullable(user);
         Optional<User> optional1 = optional.filter(v -> v.getUsername().equals("我是小四哥"));
         System.out.println(optional1);
     }
 }


不符合规则,返回空Optional(Optional.empty)


 public class OptionalTest {
     public static void main(String[] args) {
         User user = new User();
         user.setUsername("我是小四哥");
         Optional<User> optional = Optional.ofNullable(user);
         Optional<User> optional1 = optional.filter(v -> v.getUsername().equals("我不是小四哥"));
         System.out.println(optional1);
     }
 }


map(Function<? super T, ? extends U> mapper)


参数是一个Function函数式接口,会将Optional中的值作为参数传递到map中,如果传入的值为空,则返回一空的Optional对象,相当于Optional.empty(), 如果不为空,我们可以返回一个可以描述描述结果的返回值(Optional中的值,这个值可以重新赋值),如下面的返回一个tempUser


Optional中的值为空


 public class OptionalTest {
     public static void main(String[] args) {
         User user = null;
         Optional<String> optional = Optional.ofNullable(user).map(OptionalTest::getMap);
         System.out.println(optional); //Optional.empty
     }
 ​
     public static String getMap(User user){
         return user.getUsername();
     }
 }


Optional中的值不为空


 public class OptionalTest {
     public static void main(String[] args) {
         User user = new User();
         user.setUsername("我是小四哥");
         user.setAge(20);
         Optional<String> optional = Optional.ofNullable(user).map(OptionalTest::getMap);
         System.out.println(optional); // Optional[我是小四哥]
     }
 ​
     public static String getMap(User user){
         return user.getUsername();
     }
 }


flatMap(Function<? super T, Optional> mapper)


如果Optional中值存在,那么返回一个基于Optional的值(如Optional),如果Optional中的值不存在,则返回一空的Optional对象,相当于Optional.empty(),与map不同, map返回的是一个值,而flatMap返回一个基于Optional的值


 public class OptionalTest {
     public static void main(String[] args) {
         User user = new User();
         user.setUsername("我是小四哥");
         user.setAge(20);
         Optional<String> optional = Optional.ofNullable(user).flatMap(OptionalTest::getFlatMap);
         System.out.println(optional); 
     }
 ​
     public static Optional<String> getFlatMap(User user){
         return Optional.ofNullable(user).map(User::getUsername);
     }
 }


orElse(T other)


如果Optional中的值不为空,则返回Optional中的值,如果为空,则返回other值,


 String value = "2";
 String orElse = Optional.ofNullable(value).orElse("1");  
 System.out.println(orElse);  //2  
         
 String value = null;
 String orElse = Optional.ofNullable(value).orElse("1"); 
 System.out.println(orElse);  //1


orElseGet(Supplier<? extends T> other)


如果Optional中存在值,则返回值,否则返回other调用的结果


Optional中存在值


 public class OptionalTest {
     public static void main(String[] args) {
         String value = null;
         String orElse = Optional.ofNullable(value).orElseGet(OptionalTest::get);
         System.out.println(orElse);  // 123
     }
 ​
     public static String get(){
         return "123";
     }
 }


Optional中不存在值


 public class OptionalTest {
     public static void main(String[] args) {
         String value = "2";
         String orElse = Optional.ofNullable(value).orElseGet(OptionalTest::get);
         System.out.println(orElse);  // 2
     }
 ​
     public static String get(){
         return "123";
     }
 }


orElseThrow(Supplier<? extends X> exceptionSupplier)


如果Optional中的值存在,则返回值,值不存在,则抛出异常函数Supplier中的异常


 public class OptionalTest {
     public static void main(String[] args) {
         String value = null;
         String orElse = Optional.ofNullable(value).orElseThrow(() -> new RuntimeException("不存在值"));
         System.out.println(orElse);
     }
 }


输出


 Exception in thread "main" java.lang.RuntimeException: 不存在值
     at com.steak.javase.optional.OptionalTest.lambda$main$0(OptionalTest.java:14)
     at java.util.Optional.orElseThrow(Optional.java:290)
     at com.steak.javase.optional.OptionalTest.main(OptionalTest.java:13)


实战,去除if判断


我们将一个从远程接口获取了一个用户的信息,包含家庭信息,学历信息,个人信息,然后封装成一个VO,再返回前端进行展示。


家庭实体Family


 /**
  * @author 刘牌
  * @date 2022-03-3023:22
  */
 @Data
 @Accessors(chain = true)
 public class Family {
     private String fatherName;
     private String motherName;
 }


学历实体Education


 @Data
 @Accessors(chain = true)
 public class Education {
     private String education;
     private String schoolName;
     private Date admissionTime;
     private Date graduationTime;
 }


用户信息实体UserInfo


 /**
  * @author 刘牌
  * @date 2022-03-3023:16
  */
 @Data
 @Accessors(chain = true)
 public class UserInfo {
     private String name;
     private Integer age;
     private Family family;
     private Education education;
 }


用户VO,返回前端的视图对象


 /**
  * @author 刘牌
  * @date 2022-03-2922:02
  */
 @Data
 @Accessors(chain = true)
 public class UserVO {
     private String username;
     private Integer userAge;
     private String edu;
     private String school;
     private Date admissionDate;
     private Date graduationDate;
     private String mother;
     private String father;
 }


如果没有做判空处理,如下代码,因为getUser()接口中并没有为family属性设值,所以为null,那么main方法中对其进行赋值的时候,肯定会抛出空指针异常NullPointerException。


 /**
  * @author 刘牌
  * @date 2022-03-2921:52
  */
 public class OptionalTest {
     public static void main(String[] args) {
         UserInfo userInfo = getUser();
         UserVO user = new UserVO();
         user.setUsername(userInfo.getName()).setUserAge(userInfo.getAge())
                 .setEdu(userInfo.getEducation().getEducation())
                 .setSchool(userInfo.getEducation().getSchoolName())
                 .setAdmissionDate(userInfo.getEducation().getAdmissionTime())
                 .setGraduationDate(userInfo.getEducation().getGraduationTime())
                 .setFather(userInfo.getFamily().getFatherName())
                 .setMother(userInfo.getFamily().getMotherName());
         System.out.println(user);
     }
 ​
     public static UserInfo getUser(){
         Family family = new Family().setFatherName("father")
                 .setMotherName("mother");
         Education education = new Education().setEducation("本科")
                 .setSchoolName("家里蹲大学")
                 .setAdmissionTime(new Date())
                 .setGraduationTime(new Date());
         return new UserInfo()
                 .setName("小四哥")
                 .setAge(24)
                 .setEducation(education);
     }
 }


所以我们需要做判空校验,那么大多数人肯定会使用如下方式进行判断,先判断userInfo是否null,再接着判断education属性和family属性是否为null,为null不赋值,这样就能避免空指针,这是绝大多数人都会这样做的,这样做确实是没错的,但是我们发现代码中存在很多if判空操作,看起来其实不怎么好看。


 if (null != userInfo){
     user.setUsername(userInfo.getName()).setUserAge(userInfo.getAge());
     if (null != userInfo.getEducation()){
         user.setEdu(userInfo.getEducation().getEducation())
                 .setSchool(userInfo.getEducation().getSchoolName())
                 .setAdmissionDate(userInfo.getEducation().getAdmissionTime())
                 .setGraduationDate(userInfo.getEducation().getGraduationTime());
     }
     if (null != userInfo.getFamily()){
         user.setFather(userInfo.getFamily().getFatherName())
                 .setMother(userInfo.getFamily().getMotherName());
     }
 }


使用Optional接口进行改造,额~~~,这好像也没改造出啥东西来啊,没错,确实没改造出什么新花样来,除了增加一些函数操作,基本没啥改变,但是我们能直观的看出,代码比上面的会好维护一点,因为大家都比较烦if,那么,除了好看一点,好维护一点,还有啥好处呢,我觉得如果你对一些返回的结果不能很确定其返回值值的情况下,那么使用Optional来避免空指针是一个很好的办法,因为在开发中可能并不会想得那么周到,可能某处因为疏忽或者没考虑到,忘记加了if判空,那么后续可能会导致空指针,如果使用Optional的话,那么这个问题能够得到避免。


 Optional.ofNullable(userInfo).ifPresent(userInfoI -> {
     user.setUsername(userInfoI.getName()).setUserAge(userInfoI.getAge());
     Optional.ofNullable(userInfoI.getFamily()).ifPresent(family -> {
         user.setFather(userInfo.getFamily().getFatherName()).setMother(userInfo.getFamily().getMotherName());
     });
     Optional.ofNullable(userInfoI.getEducation()).ifPresent(education -> {
         user.setEdu(userInfo.getEducation().getEducation())
                 .setSchool(userInfo.getEducation().getSchoolName())
                 .setAdmissionDate(userInfo.getEducation().getAdmissionTime())
                 .setGraduationDate(userInfo.getEducation().getGraduationTime());
     });
 });


获取用户毕业时间,去除if多重判断


不使用Optional,使用if判断


 public static Date getGraduationTime(UserInfo userInfo){
     if (null != userInfo){
         if (null != userInfo.getEducation()){
             return userInfo.getEducation().getGraduationTime();
         }
     }
     return null;
 }


使用Optional


 public static Date getGraduationTime(UserInfo userInfo){
         return Optional.ofNullable(userInfo)
                 .map(UserInfo::getEducation)
                 .map(Education::getGraduationTime)
                 .orElse(null);
 }


关于Optional,里面还有很多好用的方法和操作,我们就不展开了。


今天的分享就到这里,感谢你的观看,我们下期见!

目录
相关文章
|
1月前
|
Java
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
59 1
|
23天前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
48 24
|
5天前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
40 2
|
19天前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
55 5
|
19天前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
46 5
|
21天前
|
Java API 开发者
Java中的Lambda表达式:简洁代码的利器####
本文探讨了Java中Lambda表达式的概念、用途及其在简化代码和提高开发效率方面的显著作用。通过具体实例,展示了Lambda表达式如何在Java 8及更高版本中替代传统的匿名内部类,使代码更加简洁易读。文章还简要介绍了Lambda表达式的语法和常见用法,帮助开发者更好地理解和应用这一强大的工具。 ####
|
25天前
|
Java API Maven
商汤人像如何对接?Java代码如何写?
商汤人像如何对接?Java代码如何写?
34 5
|
26天前
|
Java
在Java中实现接口的具体代码示例
可以根据具体的需求,创建更多的类来实现这个接口,以满足不同形状的计算需求。希望这个示例对你理解在 Java 中如何实现接口有所帮助。
41 1
|
18天前
|
安全 Java API
Java中的Lambda表达式:简化代码的现代魔法
在Java 8的发布中,Lambda表达式的引入无疑是一场编程范式的革命。它不仅让代码变得更加简洁,还使得函数式编程在Java中成为可能。本文将深入探讨Lambda表达式如何改变我们编写和维护Java代码的方式,以及它是如何提升我们编码效率的。
|
23天前
|
Java
Java将OffsetDateTime格式化为 yyyy-MM-dd HH:mm:ss 如何写代码?
Java将OffsetDateTime格式化为 yyyy-MM-dd HH:mm:ss 如何写代码?
26 0