網頁

2020/6/18

Effective Java 3e - Item 55: Return optionals judiciously 筆記

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>等,因為必須從兩層包裝中才能取值,改用OptionalIntOptionalLongOptionalDouble

不要把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時出現的疑惑都在本節獲得解答。


沒有留言:

張貼留言