寫程式時常常會意外遇到NullPointerException的情形,常發生在開發者沒注意或不清楚函式是否會回傳null而沒有檢查,或者撰寫函式時,由於沒有資料或不知道要回傳什麼就直覺回傳null,因此就常常發生此種情況。
Optional就是用來改進這種常遇到null而發生錯誤的情形而產生的。一個Optional
譬如,以ID來取得一個員工的姓名,用傳統的作法來檢查是否為null:
String name = getEmployName("S1233"); //回傳String或null
if(name != null){ //檢查是否為null
return name;
}else{
return "not exist";
}
如果將getEmployName()的回傳值用Optional包起來(也就是回傳的是Optional<String>),就會像這樣:
String nameOptional = getEmploynName("S1233"); //回傳Optional<String>物件
if(nameOptional.isPresent()){ //檢查Optional中是否有包含物件
return nameOptional.get();
}else{
return "not exist";
}
不過這樣看起來似乎沒有比較簡單?使用Optional的重點在於:要嘛取出所包含的值,要嘛就是產生替代值。 我們將上面的程式碼再改一次:
String nameOptional = getEmploynName("S1233"); //回傳Optionall<Employ>物件或null
//丟出替代字串
return nameOptional.orElse("not exist");
//或丟出函式回傳的值
return nameOptional.orElseGet(() -> this.getWrongMessage());
//或丟出異常
return nameOptional.orElseThrow(NoSuchElementException::new);
如果要將一個值用Optional包裝起來,可以用Optional.of()或Optional.ofNullable()方法:
Optional.of(data); //確定data不是null
Optional.ofNullable(data); //不確定data會不會是null,一種過渡方法
Optional.ofNullable(null); //產生一個包含null的Optional
Optional.empty(); //同上
如果Optional中有包含值,還可以再針對元素做處理:
Optional.ofNullable(name).map(String::length); //回傳Optional<Integer>
Optional.ofNullable(name).ifPresent(x -> list.add(x)); //不回傳
看到map()方法,是不是覺得跟Stream很像呢?其實Optional可以把它想像成是只包含一個元素的Stream,這樣就很好理解了。因此Optional也有flatMap()方法:
Optional<Double> result = Optional.of(4.0).flatMap(Test::squareRoot).orElse(0.0);
...
public static Optional<Double> squareRoot(double x) {
return (x < 0) ? Optional.empty() : Optional.of(Math.sqrt(x));
}