java8学习:Optional的简单使用

简介: 如下代码 public class Person { private Car car; public Car getCar() { return car; } } public class Car { private Insurance insur.

内容来自《 java8实战 》,本篇文章内容均为非盈利,旨为方便自己查询、总结备份、开源分享。如有侵权请告知,马上删除。
书籍购买地址:java8实战

  • 如下代码

    public class Person {
        private Car car;
        public Car getCar() {
            return car;
        }
    }
    public class Car {
        private Insurance insurance;
        public Insurance getInsurance() {
            return insurance;
        }
    }
    public class Insurance{
        private String name;
        public String getName() {
            return name;
        }
    }
    //将要使用的代码
    public String getCarInsuranceName(Person person){
        return person.getCar().getInsurance().getName();
    }
  • 如上代码如果使用,如果某个Person没有车,那么就会引发空指针异常,在平常我们使用if来去判断的,比如

    public String getCarInsuranceName(Person person){
        if (null != person){
            Car car = person.getCar();
            if (null != car){
                Insurance insurance = car.getInsurance();
                if (insurance != null) {
                    return insurance.getName();
                }
            }
        }
        return "UnKnow";
    }
  • 或者更容易读的是这样的,避免了if的嵌套难以阅读

    public String getCarInsuranceName(Person person){
        if (person == null) {
            return "UnKnow";
        }
        Car car = person.getCar();
        if (car == null){
            return "UnKnow";
        }
        Insurance insurance = car.getInsurance();
        if (insurance == null) {
            return "UnKnow";
        }
        return insurance.getName();
    }
  • 如上null的解决办法使用中的,并且不容易阅读,java8使用了Optional来解决null问题

markdown_img_paste_20181122155551525

  • Optional只能包含一个对象,对象存在的时候,Optional只是对对象的简单封装,如果没有对象,那么缺失的值被建模成一个空的Optional对象,有方法Optional.empty()返回
  • null和Optional的区别:null一定会触发空指针异常,而Optional.empty()就没有事,因为他是一个有效对象,是Optional 的单一实例.
  • 使用Optional重新定义bean对象

    public class Person {
          private Optional<Car> car;
          public Optional<Car> getCar() {
            return car;
          }
    }
    public class Car {
          private Optional<Insurance> insurance;
          public Optional<Insurance> getInsurance() {
              return insurance;
          }
    }
    public class Insurance{
          private String name;   //公司肯定有名字
          public String getName() {
              return name;
          }
    }
  • 上面中Person中的car类型是Optional,很明确的表达了Person可能有car对象也可能没有,同样对car的引用做了保证,有car的话就是car对象,没有car 的话就是Optional.empty()
  • Insurance中name并没有加Optional,因为公司肯定是有名字的,如果name为空只能代表参数是错误的,而这里如果加上Optional只能掩盖错误发生

Optional的创建

  • 空对象:Optional.empty()
  • 依靠一个非空对象创建Optional:Optional.of(notnullobj),如果notnullobj是一个空对象,那么就会抛出空指针异常
  • 可接受null对象的Optional:Optional.ofNullable(car),car对象可以是空对象也可以不是空对象,如果是空对象则得到一个空的Optional

使用map从Optional中提取和转换值

String name = null;
if (insurance != null){
    name = insurance.getName();
}
  • 如上是原来的提取的代码,先判断在取值,避免空指针,如下使用Optional

    Optional<String> name = Optional.ofNullable(insurance).map(Insurance::getName);
    • map函数会应用于流的每个元素上,然后返回name,可以把Optional看作是一个特殊的集合数据,至多包含一个元素,如果insurance包含值,那么就交给map处理,否则返回空Optional,就什么也不做
  • 本文开头提到的这样一连串的调用,怎么用Optional解决呢?

    //原来
    public String getCarInsuranceName(Person person){
        return person.getCar().getInsurance().getName();
    }
    • 我们是用如下代码可不可以呢 ?
    public String getCarInsuranceName(Optional<Person> person){
        person.map(Person::getCar)
                .map(Car::getInsurance)
                .map(Insurance::getName);
    }
    • 如上代码是编译通过不了的,因为person对象是一个Optional对象,那么他调用map将会返回一个Optional>,这显然是错误的
    • 之前我们在Stream遇到同样的问题,当时是用flatMap解决的,在这同样适用,如下
    public String getCarInsuranceName(Optional<Person> person){
        return person.flatMap(Person::getCar)
                .flatMap(Car::getInsurance)
                .map(Insurance::getName)
                .orElse("Unknow");
    }
    • 如上我们很清楚的就可以知道哪些对象可能是null,并且省去了if语句的平判断,在最后orElse:如果map得到的是null,那么就会有默认的UnKnow替代null,以防止发生空指针

Optional无法序列化

  • 为什么?

    • 如上代码中我们展示了使用Optional去构建bean,将允许缺失或者暂时无定义的变量值用特殊的形式标记出来,但是Optional的设计初衷并不是这样的,它的设计初衷仅仅是要支持能返回Optional的语法,由于它设计时就没有考虑将其作为类的字段使用,所以它也并未实现序列化接口,所以如果在框架或者序列化库中使用了 Optional修饰字段,那么可能会引发错误
    • 但是如上我们看到了,Optional应用到bean中也是不错的,能够清楚的反映出那些字段是有可能为null的,并且可以使用Optional的特性,可以这样在bean中应用Optional
    public class Car {
        private Insurance insurance;
        public Optional<Insurance> getInsuranceAsOptional() {
            return Optional.ofNullable(insurance);
        }
    }

使用filter剔除特定的值

  • 如果需要判断某个公司,那么我们需要这样的判断

    Insurance insurance = ...;
    if (null != insurance && "lalala".equals(insurance.getName())){
                System.out.println("...");
    }
  • 使用filter方法

    Optional<Insurance> insurance = null;
    insurance.filter(i -> "lalala".equals(i.getName()))
            .ifPresent(i -> System.out.println("..."));
    • 如上的ifPresent方法是判断i是否是空值,不是空值就执行后面的输出,是空即什么都不做

异常与Optional对象

  • String转换为Integer对象,如果转换错误就会爆数字格式化异常,我们必须try上异常以处理异常
  • 需求:输入参数转换为int,然后返回该转换后的值,出错的话就返回0

    public Integer StringParse(String str){
        if (null == str) return 0;
        try {
            return Integer.parseInt(str);
        }catch (NumberFormatException e){
            return 0;
        }
    }
  • 用Optional解决

    public Optional<Integer> StringParse(String str){
        try {
            return Optional.of(Integer.parseInt(str));
        }catch (NumberFormatException e){
            return Optional.empty();
        }
    }

避免使用基本类型的Optional对象

  • 对于之前的函数式接口,我们提到的如果基本类型比较多,那么就优先使用对应的基本类型的函数式接口,比如IntFunction,但是Optional不推荐使用OptionalInt等类似的基本类型对象,因为这些对象中并没有map和filter等方法
目录
相关文章
|
15天前
|
消息中间件 前端开发 Java
java学习路径
【4月更文挑战第9天】java学习路径
17 1
|
1月前
|
安全 Java 程序员
学习Java类加载机制
在Java的世界里,每一个类或者接口,在经历编译器后,都会生成一个个.class文件。
18 0
|
1月前
|
Java 关系型数据库 MySQL
37、一篇文章学习 Java 中的日期相关类(Date 和 Calendar),非常常用
37、一篇文章学习 Java 中的日期相关类(Date 和 Calendar),非常常用
27 0
|
15天前
|
设计模式 前端开发 安全
Java是一种广泛使用的编程语言,其学习路径可以大致分为以下几个阶段
【4月更文挑战第9天】Java是一种广泛使用的编程语言,其学习路径可以大致分为以下几个阶段
15 1
|
1月前
|
Java 索引
Java中String方法学习总结_kaic
Java中String方法学习总结_kaic
|
5天前
|
JavaScript Java 测试技术
基于Java的驾考自主学习预约平台的设计与实现(源码+lw+部署文档+讲解等)
基于Java的驾考自主学习预约平台的设计与实现(源码+lw+部署文档+讲解等)
17 0
|
6天前
|
JavaScript Java 测试技术
基于Java的精品课程在线学习系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的精品课程在线学习系统的设计与实现(源码+lw+部署文档+讲解等)
25 1
|
6天前
|
JavaScript Java 测试技术
基于Java的中文学习系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的中文学习系统的设计与实现(源码+lw+部署文档+讲解等)
22 0
|
12天前
|
Java 存储
键值之道:深入学习Java中强大的HashMap(二)
键值之道:深入学习Java中强大的HashMap
20 0
键值之道:深入学习Java中强大的HashMap(二)
|
14天前
|
JavaScript Java 测试技术
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
30 0
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)