jdk1.8 -- optional 的使用

一.optional的介绍

  Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

  Optional 类的引入很好的解决空指针异常。

  jdk1.8 -- optional 的使用

  本文将从三方面来讲解optional:

  1.Optional的构建

  2.Optional的获取

  3.Optional的复合操作

下面先讲解在没有Optional之前我们是如何对null值进行判断的

class Persion{
    
    private Car car;
    
    public Car getCar() {
        return this.car;
    }
}

class Car{
    
    private Brand insurance;
    
    public Brand getInsurance() {
        return this.insurance;
    }
}
class Brand {
    private String name;
    
    public String getName() {
        return this.name;
    }
}
public class BeforeOptional { public static void main(String[] args) { getBrandName(new Persion()); getBrandNameDefault(new Persion()); } private static String getBrandName(Persion persion) { if(null !=persion.getCar()) { Car car = persion.getCar(); if(null !=car.getInsurance()) { Brand insurance = car.getInsurance(); if(null !=insurance.getName()) { return insurance.getName(); } } } return ""; } private static String getBrandNameDefault(Persion persion) { String defaultValue = "UNKNOW"; if(null ==persion) return defaultValue; Car car = persion.getCar(); if(null == car) return defaultValue; Brand insurance = car.getInsurance(); if(null == insurance) return defaultValue; return insurance.getName(); } }

显然,我们需要通过代码来硬编码实现对象引用变量的判断

二.Optional API的操作

    //********************** 1. Optional 的构建********************** 
        
        //1.1创建一个空的optional(内部new了一个空的optional),不支持get方法,会报异常NoSuchElementException
        Optional<Brand> empty = Optional.<Brand>empty();
        empty.get();
        
        //1.2创建一个optional,传入的值不能为null,返回Optional<Object>,为null时会报NullPointerException
        Optional<Brand> of = Optional.of(new Brand());
        System.out.println(of.get());
        
        //1.3创建一个可空可有的optional,对前2种的总结(如果传null,走empty方法,非null,走of方法)
        Optional<Brand> brand = Optional.ofNullable(new Brand());
        Optional<Object> ofNullable2 = Optional.ofNullable(null);
    
        //********************** 2. Optional 的获取操作**********************
        
        //2.1 如果当前有值,返回这个值,否则报NoSuchElementException("No value present");
        brand.get();
        
        //2.2 如果有值,会传出insurance实例,如果没值,会给出传入的参数;(参数是supplier)
        brand.orElseGet(Brand::new);
        
        //2.3 如果有值,会传出insurance实例,如果没值,会给出传入的参数;(参数是Insurance 实例)
        brand.orElse(new Brand());
        
        //2.4 如果有值,会传出insurance实例,如果没值,可以抛出异常
        brand.orElseThrow(RuntimeException::new);
        brand.orElseThrow(()->new RuntimeException("not have reference"));
        
        
        //********************** 3. Optional 的复合操作**********************
        
        //3.1 返回一个boolean值
        brand.isPresent();
        
        //3.2 如果有值,有值时可以进行操作(consumer操作)
        brand.ifPresent(System.out::println);
        
        //3.3 filter操作,它会通过predicate操作,对brand 以及表达式进行非空的验证,通过后,方能得到结果
        brand.filter(b->b.getName() == null).get();
        
        //3.4 map操作:同filter,不同之处在于map会改变get到的类型
        brand.map(b->b.getName()).get();
        
        //3.5 flatMap 得到复合操作后的Optional<flatMap参数得到的值的optional>
        Optional<Per> per = Optional.ofNullable(new Per());
        Optional<Optional<Car2>> map = per.map(Per::getCar);    //这个是对Optional<optional<Car2>进行了再一次的封装
        Optional<Car2> flatMap = per.flatMap(Per::getCar);        //这个得到的还是原来的Optional<Object> 

我们回过头来解决开篇中的方法

class Persion2{
    private Optional<Car2> car;      //注意这里要加上Optional的改写

    public Optional<Car2> getCar() {
        return car;
    }
    
}

class Car2{
    private Optional<Brand2> Brand2;  //注意这里要加上Optional的改写

    public Optional<Brand2> getBrand2() {
        return Brand2;
    }
}
class Brand2{
    private String name;
    public String getName() {
        return this.name;
    }
}

public static String getInsuranceName(Persion2 per) {
   return Optional.ofNullable(per).flatMap(Persion2::getCar).flatMap(Car2::getBrand2).map(b->b.getName()).orElse("Unknown");  //是不是一行代码就搞定了
}