码农在囧途

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

前言

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,里面还有很多好用的方法和操作,我们就不展开了。

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

聊一聊Java8 Optional,让你的代码更加优雅的更多相关文章

  1. java代码之美(16) ---Java8 Optional

    Java8 Optional 一句话介绍Optional类:使用JDK8的Optional类来防止NullPointerException(空指针异常)问题. 一.前言 在我们开放过程中,碰到的异常中 ...

  2. Java8 Optional的简单操作

    我们经常会遇到这种情况:首先判断一个对象是否为null,如果不为null,获取一个对象中的一个属性,如果该属性不为null,又获取该属性的属性,如果该属性的属性不为null,又获取属性的属性的属性: ...

  3. java8 Optional优雅非空判断

    java8 Optional优雅非空判断 import java.util.ArrayList;import java.util.List;import java.util.Optional; pub ...

  4. Java8 Optional && Guava Optional

    Java8 -- Optional boolean isPresent():与obj != null()一样:调用get()前要调用isPresent()检查,不然会报错 Optional的三种构造方 ...

  5. JDK8漫谈——代码更优雅

    简介 lambda表达式,又称闭包(Closure)或称匿名方法(anonymous method).将Lambda表达式引入JAVA中的动机源于一个叫"行为参数"的模式.这种模式 ...

  6. JAVA8-让代码更优雅之List排序

    先定义一个实体类 @Data @AllArgsConstructor @NoArgsConstructor public class Human { private String name; priv ...

  7. 用Assert(断言)封装异常,让代码更优雅(附项目源码)

    有关Assert断言大家并不陌生,我们在做单元测试的时候,看业务事务复合预期,我们可以通过断言来校验,断言常用的方法如下: public class Assert { /** * 结果 = 预期 则正 ...

  8. Lambda表达式, 可以让我们的代码更优雅.

    在C#中, 适当地使用Lambda表达式, 可以让我们的代码更优雅. 通过lambda表达式, 我们可以很方便地创建一个delegate: 下面两个语句是等价的 Code highlighting p ...

  9. CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅

    首页   登录注册         CSS 黑魔法小技巧,让你少写不必要的JS,代码更优雅 阅读 8113 收藏 927 2017-09-26 原文链接:github.com 腾讯云容器服务CSS,立 ...

随机推荐

  1. Python 爬取 "王者荣耀.英雄壁纸" 过程中的矛和盾

    1. 前言 学习爬虫,最好的方式就是自己编写爬虫程序. 爬取目标网站上的数据,理论上讲是简单的,无非就是分析页面中的资源链接.然后下载.最后保存. 但是在实施过程却会遇到一些阻碍. 很多网站为了阻止爬 ...

  2. 面试官:Redis中列表的内部实现方式是什么?

    在面试间里等候时,感觉这可真暖和呀,我那冰冷的出租屋还得盖两层被子才能睡着.正要把外套脱下来,我突然听到了门外的脚步声,随即门被打开,一位眉毛弯弯嘴唇红红的小姐姐走了进来,甜甜的香水味立刻钻进了我的鼻 ...

  3. ArcMap操作随记(13)

    1.为地图册创建定位器地图 创建数据框→标注字段(PageName)→格网索引图层[导出数据]→图层右键,[属性]|[定义查询] 2.为地图册创建动态文本 导出→[文件]|[导出地图]→PDF 3.关 ...

  4. 《前端运维》一、Linux基础--09常用软件安装

    一.软件包管理 RPM是RedHat Package Manager(RedHat软件包管理工具)类似Windows里面的"添加/删除程序".软件包有几种类型,我们一起来看下: 源 ...

  5. Linux指令入门-系统管理(云小宝码上送祝福,免费抽iphone13任务)

    码上送祝福,带云小宝回家 做任务免费抽iphone13,还可得阿里云新春限量手办 日期:2021.12.27-2022.1.16 云小宝地址:https://developer.aliyun.com/ ...

  6. 选择Key-Value Store

    [IT168 专稿]在之前的文章中,给大家介绍了<Redis快速入门:Key-Value存储系统简介>,今天进一步给大家介绍为什么选择Key-Value Store.Key-Value S ...

  7. Android 12(S) 图形显示系统 - 解读Gralloc架构及GraphicBuffer创建/传递/释放(十四)

    必读: Android 12(S) 图形显示系统 - 开篇 一.前言 在前面的文章中,已经出现过 GraphicBuffer 的身影,GraphicBuffer 是Android图形显示系统中的一个重 ...

  8. XML的解析方式有哪几种?有什么区别?

    有DOM.SAX等. DOM:(Document Object Model, 即文档对象模型) 是 W3C 组织推荐的处理 XML 的一种标准方式. DOM中的核心概念就是节点.DOM在分析XML文档 ...

  9. SQL 语言包括哪几部分?每部分都有哪些操作关键字?

    SQL 语言包括数据定义(DDL).数据操纵(DML),数据控制(DCL)和数据查询(DQL) 四个部分. 数据定义:Create Table,Alter Table,Drop Table, Crae ...

  10. Eureka和Zookeeper区别?

    (1)Eureka取CAP的AP,注重可用性,Zookeeper取CAP的CP注重一致性. (2)Zookeeper在选举期间注册服务瘫痪,虽然服务最终会恢复,但选举期间不可用. (3)eureka的 ...