在《快速学习Java8新特性第五讲——强大的Stream API》这一讲中,我就已经提及到了Optional类。在这一讲中,我将对其做一个更加细致的讲解。

Optional类是什么?

Optional类(java.util.Optional)是一个容器类,代表一个值存在或不存在,原来用null表示一个值不存在,现在使用Optional类可以更好的表达这个概念,并且它还可以避免空指针异常。

Optional类中的常用方法

Optional容器类中的常用方法有:

下面,我会举例分别一一介绍以上方法。

Optional.of(T t)

先来看一下Optional类中的of()方法。我们可以使用该方法来构建一个Optional容器类。

@Test
public void test1() {//创建一个带泛型的Optional容器类Optional<Employee> op = Optional.of(new Employee());Employee emp = op.get();System.out.println(emp);
}

其中,Employee实体类的内容如下:

package com.meimeixia.java8;public class Employee {private Integer id;private String name;private Integer age;private Double salary;private Status status;//加个状态public Employee() {super();}public Employee(Integer id) {super();this.id = id;}public Employee(Integer id, Integer age) {super();this.id = id;this.age = age;}public Employee(Integer id, String name, Integer age, Double salary) {super();this.id = id;this.name = name;this.age = age;this.salary = salary;}public Employee(Integer id, String name, Integer age, Double salary, Status status) {super();this.id = id;this.name = name;this.age = age;this.salary = salary;this.status = status;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public Double getSalary() {return salary;}public void setSalary(Double salary) {this.salary = salary;}public Status getStatus() {return status;}public void setStatus(Status status) {this.status = status;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((age == null) ? 0 : age.hashCode());result = prime * result + ((id == null) ? 0 : id.hashCode());result = prime * result + ((name == null) ? 0 : name.hashCode());result = prime * result + ((salary == null) ? 0 : salary.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Employee other = (Employee) obj;if (age == null) {if (other.age != null)return false;} else if (!age.equals(other.age))return false;if (id == null) {if (other.id != null)return false;} else if (!id.equals(other.id))return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;if (salary == null) {if (other.salary != null)return false;} else if (!salary.equals(other.salary))return false;return true;}@Overridepublic String toString() {return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + ", status=" + status+ "]";}public enum Status {FREE,BUSY,VOCATION;}}

有一点,需要引起我们的注意,of()方法中传入null,会报NullPointerException异常。

@Test
public void test1() {//创建一个带泛型的Optional容器类Optional<Employee> op = Optional.of(null);//of()方法不能构建nullEmployee emp = op.get();System.out.println(emp);
}

如果运行以上测试方法,那么你就能看到所报的NullPointerException异常了。

Optional.empty()

使用Optional类中的empty()方法可以创建一个空的Optional实例,即里面没有任何的东西。

@Test
public void test2() {Optional<Employee> op = Optional.empty();//empty()方法只是构建一个空的Optional,里面没有任何的东西System.out.println(op.get());
}

如果运行以上测试方法,那么你就会发现报了java.util.NoSuchElementException:No value present这样一个异常,如下图所示。

Optional.ofNullable(T t)

虽然Optional类中的of()方法不允许包装null,但是ofNullable()方法可以,传递到该方法中的若为null,则构建一个空的Optional实例;传递到该方法中的若为一个对象,则构建一个包装有该对象的Optional实例。实际上,ofNullable()方法是empty()方法和of()方法它俩的综合,你要不相信的话,不妨查看一下ofNullable()方法的源代码。

你可以试着运行一下以下test3()测试方法:

@Test
public void test3() {Optional<Employee> op = Optional.ofNullable(new Employee());//isPresent()方法判断Optional容器类中是否包含值if (op.isPresent()) {System.out.println(op.get());}
}

那么,你便可以在Eclipse控制台中看到如下打印内容。

如果要是将测试代码改写成下面这样,那么运行test3()测试方法之后,Eclipse控制台将会没有任何内容输出。

@Test
public void test3() {Optional<Employee> op = Optional.ofNullable(null);//isPresent()方法判断Optional容器类中是否包含值if (op.isPresent()) {System.out.println(op.get());}
}

isPresent()

isPresent()方法用于判断Optional容器类中是否包含值。演示该方法的例子已在上面给出,这里不再赘述。

orElse(T t)

如果调用对象包含有值,那么返回该值,否则返回orElse()方法中的对象。例如,有如下一段测试代码:

@Test
public void test3() {Optional<Employee> op = Optional.ofNullable(new Employee());Employee emp = op.orElse(new Employee(109, "杰哥", 18, 8889.88, Status.FREE));System.out.println(emp);
}

运行以上测试方法,你便可以在Eclipse控制台中看到如下打印内容。

如果要是将测试代码改写成下面这样:

@Test
public void test3() {Optional<Employee> op = Optional.ofNullable(null);Employee emp = op.orElse(new Employee(109, "杰哥", 18, 8889.88, Status.FREE));System.out.println(emp);
}

那么,运行以上测试方法,你便可以在Eclipse控制台中看到如下打印内容。

orElseGet(Supplier s)

如果调用对象包含有值,那么返回该值,否则返回orElseGet()方法中的供给函数获取的值。例如,有如下一段测试代码:

@Test
public void test3() {Optional<Employee> op = Optional.ofNullable(new Employee());Employee emp = op.orElseGet(() -> new Employee(109, "杰哥", 18, 8889.88, Status.FREE));System.out.println(emp);
}

运行以上测试方法,你便可以在Eclipse控制台中看到如下打印内容。

如果要是将测试代码改写成下面这样:

@Test
public void test3() {Optional<Employee> op = Optional.ofNullable(null);Employee emp = op.orElseGet(() -> new Employee(109, "杰哥", 18, 8889.88, Status.FREE));System.out.println(emp);
}

那么,运行以上测试方法,你便可以在Eclipse控制台中看到如下打印内容。

map(Function f)

若有值则对其处理,并返回处理后的Optional,否则返回Optional.empty()。为了演示该方法,可以编写如下一段测试代码进行测试。

@Test
public void test4() {Optional<Employee> op = Optional.ofNullable(new Employee(109, "杰哥", 18, 8889.88, Status.FREE));Optional<String> str = op.map((e) -> e.getName());System.out.println(str.get());
}

运行以上测试方法,你便可以在Eclipse控制台中看到如下打印内容。

flatMap(Function mapper)

与map类似,但要求返回值必须是Optional。为了演示该方法,可以编写如下一段测试代码进行测试。

@Test
public void test4() {Optional<Employee> op = Optional.ofNullable(new Employee(109, "杰哥", 18, 8889.88, Status.FREE));Optional<String> str2 = op.flatMap((e) -> Optional.of(e.getName()));//进一步地避免空指针异常System.out.println(str.get());
}

但是,你要写成下面这样,就会报错,如下图所示。

运行以上test4()测试方法,你便可以在Eclipse控制台中看到如下打印内容。

综合案例

下面,我会举一个综合案例来说明Optional类在实际开发中的使用。例如,有这样一个需求:男人心中可能会有一个女神(但并不是每一个男人心中都有一个女神),现在要获取一个男人心中女神的名字。

为了解决这样的需求,我们需要建立一个男人类和女神类:

  • 男人类,即Man.java。

    package com.meimeixia.java8;public class Man {//男人心中可能会有一个女神,但并不是每一个男人心中都有一个女神private Godness godness;public Man() {super();// TODO Auto-generated constructor stub}public Man(Godness godness) {super();this.godness = godness;}public Godness getGodness() {return godness;}public void setGodness(Godness godness) {this.godness = godness;}@Overridepublic String toString() {return "Man [godness=" + godness + "]";}}
    
  • 女神类,即Godness.java

    package com.meimeixia.java8;public class Godness {private String name;//女神肯定得有一个名字,所以这样的值没必要包装在Optional类里面public Godness() {super();// TODO Auto-generated constructor stub}public Godness(String name) {super();this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Godness [name=" + name + "]";}}
    

现在,我们要想获取一个男人心中女神的名字,可能一开始会将代码写成下面这样:

package com.meimeixia.java8;import org.junit.Test;public class OptionalDemo {//综合案例@Testpublic void test() {Man man = new Man();String name = getGodnessName(man);System.out.println(name);}//需求:获取一个男人心中女神的名字public String getGodnessName(Man man) {return man.getGodness().getName();}}

运行以上test()测试方法,你会发现报NullPointerException异常了。

这是因为并不是每一个男人心中都有一个女神,所以获取到的女神有可能为null,继而就会报NullPointerException异常。

要想解决这样的NullPointerException异常,搁之前我们是像下面这样做的:

package com.meimeixia.java8;import org.junit.Test;public class OptionalDemo {//综合案例@Testpublic void test() {Man man = new Man();String name = getGodnessName(man);System.out.println(name);}//需求:获取一个男人心中女神的名字public String getGodnessName(Man man) {// return man.getGodness().getName();if (man != null) {Godness gn = man.getGodness();if (gn != null) {return gn.getName();}}return "苍老师";}}

现在,我们知道使用Optional类可以很容易地避免控制针异常。那就使用Optional类来试试,首先,我们得重新创建一个新型男人类,即NewMan.java。

package com.meimeixia.java8;import java.util.Optional;public class NewMan {//但是,大家要注意,不给Optional赋值,即Optional没赋值,它默认是什么值?默认是nullprivate Optional<Godness> godness = Optional.empty();//把女神包装进Optional类里面public NewMan() {super();// TODO Auto-generated constructor stub}public NewMan(Optional<Godness> godness) {super();this.godness = godness;}public Optional<Godness> getGodness() {return godness;}public void setGodness(Optional<Godness> godness) {this.godness = godness;}@Overridepublic String toString() {return "NewMan [godness=" + godness + "]";}}

然后,在OptionalDemo类编写一个如下方法,用于获取一个男人心中女神的名字。

//一顿点,避免了控制针异常
public String getGodnessName2(Optional<NewMan> man) {return man.orElse(new NewMan()).getGodness().orElse(new Godness("苍老师")).getName();
}

接着,就要对以上方法进行测试了。

  • 第一种情况,测试代码如下:

    @Test
    public void test1() {Optional<NewMan> op = Optional.ofNullable(null);String str = getGodnessName2(op);System.out.println(str);
    }
    

    运行以上测试方法,你便可以在Eclipse控制台中看到如下打印内容。

  • 第二种情况,测试代码如下:

    @Test
    public void test1() {Optional<NewMan> op = Optional.ofNullable(new NewMan());String str = getGodnessName2(op);System.out.println(str);
    }
    

    运行以上测试方法,你也可以在Eclipse控制台中看到如下打印内容。

  • 第三种情况,测试代码如下:

    @Test
    public void test1() {Optional<Godness> gn = Optional.ofNullable(null);Optional<NewMan> op = Optional.ofNullable(new NewMan(gn));String str = getGodnessName2(op);System.out.println(str);
    }
    

    运行以上测试方法,你依然可以在Eclipse控制台中看到如下打印内容。

  • 第四种情况,测试代码如下:

    @Test
    public void test1() {Optional<Godness> gn = Optional.ofNullable(new Godness("波多野结衣老师"));Optional<NewMan> op = Optional.ofNullable(new NewMan(gn));String str = getGodnessName2(op);System.out.println(str);
    }
    

    运行以上测试方法,你便可以在Eclipse控制台中看到如下打印内容。

小结

总之这个Optional类其实就是一个封装了一个元素的容器,而这个元素可以是null也可以是其它任意类型的,合理利用Optional类可以很好地避免程序中出现的空指针异常。

快速学习Java8新特性第七讲——Optional类相关推荐

  1. java8新特性(5)— Optional 类

    java8新特性(5)- Optional 类 空指针解决方案 package com.common.jdk8;import java.util.Optional;//Optional 类是一个可以为 ...

  2. 【Java8新特性】关于Java8的Stream API,看这一篇就够了!!

    写在前面 Java8中有两大最为重要的改变.第一个是 Lambda 表达式:另外一个则是 Stream API(java.util.stream.*)  ,那什么是Stream API呢?Java8中 ...

  3. 【Java8新特性】浅谈方法引用和构造器引用

    写在前面 Java8中一个很牛逼的新特性就是方法引用和构造器引用,为什么说它很牛逼呢?往下看! 方法引用 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!这里需要注意的是:实现抽 ...

  4. 【Java8新特性】关于Java8中的日期时间API,你需要掌握这些!!

    写在前面 Java8之前的日期和时间API,存在一些问题,比如:线程安全的问题,跨年的问题等等.这些问题都在Hava8中的日期和时间API中得到了解决,而且Java8中的日期和时间API更加强大.立志 ...

  5. java8新特性-lambda表达式入门学习

    定义 jdk8发布新特性中,lambda是一大亮点之一.lambda表达式能够简化我们对数据的操作,减少代码量,大大提升我们的开发效率.Lambda 表达式"(lambda expressi ...

  6. Java8新特性学习记录

    前言: Java 8 已经发布很久了,很多报道表明Java 8 是一次重大的版本升级.在Java Code Geeks上已经有很多介绍Java 8新特性的文章, 例如Playing with Java ...

  7. 【Java学习笔记之二十八】深入了解Java8新特性

    前言: Java 8 已经发布很久了,很多报道表明java 8 是一次重大的版本升级.在Java Code Geeks上已经有很多介绍Java 8新特性的文章,例如Playing with Java ...

  8. Java8新特性学习_001_(Lambda表达式,函数式接口,方法引用,Stream类,Optional类)

    目录 ■代码 ■代码运行结果 ■代码说明 ・44行:Stream的.foreach方法ー参数类型:函数式接口 ・82行:Interface中,default方法 ・92行   Stream的.max方 ...

  9. 零基础学习java------21---------动态代理,java8新特性(lambda, stream,DateApi)

    1. 动态代理 在一个方法前后加内容,最简单直观的方法就是直接在代码上加内容(如数据库中的事务),但这样写不够灵活,并且代码可维护性差,所以就需要引入动态代理 1.1 静态代理实现 在讲动态代理之前, ...

最新文章

  1. 海思3559A上编译libjpeg-turbo源码操作步骤
  2. CI框架css引入出现问题
  3. pytorch_导入d2l_pytorch包问题
  4. 【原生JS插件】LoadingBar页面顶部加载进度条
  5. 【转】_declspec(naked) 使用
  6. 西澳大学商科专业排名_澳洲西澳大学优势专业排名多少
  7. Jquery特殊效果
  8. Leetcode算法题(C语言)5--存在重复
  9. Linux中7个判断文件系统类型的方法
  10. Haproxy+Nginx实现web负载均衡群集
  11. win7 安装 vmware出错: failed to create the requested registry key key installer error 1021 的解决办法。...
  12. cobar php,cobar配置安装_MySQL
  13. Pandas数据分析
  14. Codeforces 1010D Mars rover
  15. python加减乘除运算代码_四则运算python版
  16. 腾讯视频没有了html分享代码,腾讯视频代码在哪里 腾讯视频嵌入网页的方法-电脑教程...
  17. linux原生运行微信客户端,巧用 Docker 在 Linux 下 运行微信 PC 客户端
  18. Led智慧照明系统功能
  19. matlab可以仿真特殊电机,基于Matlab的异步电动机矢量控制系统的仿真研究
  20. VBA For Each循环

热门文章

  1. Vue中key属性的作用
  2. java科技说明文范文800_说明文范文:生活因成功而精彩
  3. 【PHP小皮】使用教程
  4. Unreal中的Cross Product(向量积)方向定义
  5. 精仿互站模板 友价源码商城T5内核二次开发运营版
  6. html中url英文全称,URL的英文全称
  7. SpringBoot POI Word合并
  8. Mysql+Echarts+Python+Flask实现前后端交互及数据可视化
  9. Rust交叉编译开发环境的搭建
  10. Mac Office 怎么设置单面打印