天天看點

Optional類

前言

建構Person/Car/Insurance的資料模型

//人
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();
}
           

java.lang.NullPointerException異常

null值檢查

//1.深度質疑
public String getCarInsuranceName(Person person) {
    if (person != null) {
        Car car = person.getCar();
        if (car != null) {
            Insurance insurance = car.getInsurance();
            if (insurance != null) {
                return insurance.getName();
            }
        }
    }
    return "Unknown";
}
//2.退出語句
public String getCarInsuranceName(Person person) {
    if (person == null) {
        return "Unknown";
    }
    Car car = person.getCar();
    if (car == null) {
        return "Unknown";
    }
    Insurance insurance = car.getInsurance();
    if (insurance == null) {
        return "Unknown";
    }
    return insurance.getName();
}
           

Optional

Optional是對值的簡單封裝,說明值要麼存在,要麼不存在。

建立Optional對象

  1. 聲明一個空的Optional

Optional<Car> optCar = Optional.empty();

  1. 依據一個非空值建立Optional

Optional<Car> optCar = Optional.of(car);

  1. 可接受null的Optional

Optional<Car> optCar = Optional.ofNullable(car);

使用map從Optional對象中提取和轉換值

String name = null;
if(insurance != null){
    name = insurance.getName();
}

//優化後
Optional<Insurance> optInsurance = Optional.ofNullable(insurance);
Optional<String> name = optInsurance.map(Insurance::getName);

           

使用flatMap連結Optional對象

public String getCarInsuranceName(Person person) {
    return person.getCar().getInsurance().getName();
}
           

應對剛開始的資料模型

Optional<Person> optPerson = Optional.of(person);
Optional<String> name =
    optPerson.map(Person::getCar)
             .map(Car::getInsurance)
             .map(Insurance::getName);
           

重新設計資料模型

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; }
}
           

取值

Optional<Person> optPerson = Optional.of(person);
Optional<String> name =
    optPerson.flatMap(Person::getCar)
             .flatMap(Car::getInsurance)
             .map(Insurance::getName)
             .orElse("Unknown");
           

預設行為及解引用 Optional 對象

采用orElse方法讀取這個變量的值,使用這種方式你還可以定義一個預設值,遭 遇空的Optional變量時,預設值會作為該方法的調用傳回值。 Optional類提供了多種方法讀取 Optional執行個體中的變量值

  • get()是這些方法中最簡單但又最不安全的方法。如果變量存在,它直接傳回封裝的變量 值,否則就抛出一個NoSuchElementException異常。是以,除非你非常确定Optional 變量一定包含值,否則使用這個方法是個相當糟糕的主意。此外,這種方式即便相對于 嵌套式的null檢查,也并未展現出多大的改進。
  • orElse(T other)是我們在代碼清單10-5中使用的方法,正如之前提到的,它允許你在 Optional對象不包含值時提供一個預設值。
  • orElseGet(Supplier<? extends T> other)是orElse方法的延遲調用版, Supplier 方法隻有在Optional對象不含值時才執行調用。如果建立預設值是件耗時費力的工作, 你應該考慮采用這種方式(借此提升程式的性能),或者你需要非常确定某個方法僅在 Optional為空時才進行調用,也可以考慮該方式(這種情況有嚴格的限制條件)。
  • orElseThrow(Supplier<? extends X> exceptionSupplier)和get方法非常類似, 它們遭遇Optional對象為空時都會抛出一個異常,但是使用orElseThrow你可以定制希 望抛出的異常類型。
  • ifPresent(Consumer<? super T>)讓你能在變量值存在時執行一個作為參數傳入的 方法,否則就不進行任何操作。

Optional提供的方法 

Optional類
Optional類