Effective Java 3e - Item55: Return optionals judiciously 回傳Optional。
在Java 8以前,方法若無法回傳值,只能回傳null或丟出例外(exception)。但這兩種做法的缺點分別是,回傳null則客戶端必須檢查回傳值是否為null,這就是常導致NullPointerException
的原因;而丟出例外的成本很高,因為產生例外必須獲取整個執行堆疊(stack trace)。
Java 8多了Optional<T>
來替代返回null或丟出exception的做法。
Optional
為不可變的(immutable)的單一物件容器。Optional
可視為一種只能持有單一元素的不可變集合(immutable collections)。
方法簽章(method signature)回傳型態為Optional
時則方法不應回傳null,因為這樣就失去使用Optional
的目的。
Optional<Employee> getEmployee(long id) {
// some logic
return null;// WRONG! DO NOT return null if employee not found
}
Optional
迫使客戶端必須處理結果可能為空的情況。
例如在以前客戶端若沒有對回傳結果判斷null,可能導致NullPointerException
。
Employee employee = getEmployee(id);
if (employee != null) { // <-- cause NullPointerException if ignore this checking null logic
// ...
}
若改回傳Optional
則客戶端一定要處理結果為空的情況。
Employee employee1 = getEmployee(id).orElse(new Employee()); // 改回傳一個預設值
Employee employee2 = getEmployee(id).orElseGet(() -> {
Employee emp = new Employee(); // 回傳一個預設值及預設屬性
// some setting logic
});
Employee employee3 = getEmployee(id).orElseThrow(Exception::new); // 丟出例外
對於回傳的集合物件或陣列不要用Optional
包裝,而應回傳空的集合。
Optional
是要耗費成本的,不適合在對效能極度要求的環境中使用。
不要用Optional
包裝原始型別的包裝類別(boxed primitive type),也就是Optional<Integer>
、Optional<Long>
、Optional<Double>
等,因為必須從兩層包裝中才能取值,改用OptionalInt
、OptionalLong
、OptionalDouble
。
不要把Optional
作為集合或陣列的元素,key,類別的成員。
Map<Integer, Optional<Employee>> employeeOptMap = new HashMap<>(); // DO NOT use Optional as Map elements
Map<Optional<String>, Employee> employeeMap = new HashMap<>(); // DO NOT use Optional as Map keys
List<Optional<Employee>> employeeOptList = new ArrayList<>(); // DO NOT use Optional as Collection elements
Optional<String>[] nameOpts[] = new Optional<String>[]; // DO NOT use Optional Array
class Employee {
private Optional<String> nameOpt; // DO NOT use Optional as instance field
}
約兩年前開始使用Optional
時出現的疑惑都在本節獲得解答。
沒有留言:
張貼留言