【JAVA8新特性】- 使用Optional取代null

Optional

在Java中對一個空對象進行操作時,便會拋出最常見的異常NullPointerException。為了改善這個問題,Java8中提供了一個java.util.Optional<T>類型。

Optional類的Javadoc描述如下:這是一個可以為null的容器對象。如果值存在isPresent()方法會返回true,調用get()方法會返回該對象。

1. 示例1:

下面介紹Optional類的使用方法。 假如有一個像下面這樣的類層次結構:

@Data
public class Department {

    private Employee employee;

    public Department(Employee employee) {
        this.employee = employee;
    }
}
@Data
class Employee{
    private Girl girlFriend;

    public Employee(Girl girlFriend) {
        this.girlFriend = girlFriend;
    }
}

@Data
class Girl{
    private String name;

    public Girl(String name) {
        this.name = name;
    }
}

部門Department類包含一個員工employee屬性,類型為Employee,員工Employee類包含girlFriend屬性,類型為Girl。假如現(xiàn)在要獲取部門某個員工的女朋友,我們通常是這樣獲取的:

    public String getGirlFriend(Department department){
        if(department !=null){
            Employee employee = department.getEmployee();
            if(employee !=null){
                Girl girl = employee.getGirlFriend();
                if(girl!=null){
                    return girl.getName();
                }
                return "單身狗";
            }
            return "沒有員工";
        }
        return "部門為空";
    }

可以看到,在每次引用變量的屬性時,都要先判斷變量是否為空,如果不做該檢查將可能導致NullPointerException。下面我們將使用Optional來改善這種層層嵌套,啰嗦的代碼。

    public String getGirlFriend2(Department department){
        Optional<Department> opt = Optional.ofNullable(department);
        return opt.map(Department::getEmployee)
                .map(Employee::getGirlFriend)
                .map(Girl::getName)
                .orElseThrow(NoSuchFieldError::new);

        // 如果發(fā)生NPE異常,則返回默認String "default"
        String girlName = opt.map(Department::getEmployee)
                .map(Employee::getGirl)
                .map(Girl::getName)
                .orElse("default");
    }

2. 示例2:

public class MainDemo {

    public static void main(String[] args) {
        Integer value1 = null;
        Integer value2 = new Integer(10);

        // Optional.ofNullable - 允許傳遞為null參數(shù)
        Optional<Integer> a = Optional.ofNullable(value1);
        // Optional.of - 如果傳遞的參數(shù)是null,拋出異常NullPointException
        Optional<Integer> b = Optional.of(value2);

        System.out.println(sum(a, b));
    }

    private static Integer sum(Optional<Integer> a, Optional<Integer> b) {
        // Optional.isPresent - 判斷值是否存在
        System.out.println("第一個參數(shù)值存在:" + a.isPresent());
        System.out.println("第二個參數(shù)值存在:" + b.isPresent());

        // Optional.orElse - 如果值存在,返回它,否則返回默認值
        Integer value1 = a.orElse(new Integer(0));

        Integer value2 = b.get();

        return value1 + value2;
    }
}

輸出:

第一個參數(shù)值存在:false
第二個參數(shù)值存在:true
10

下面我們來具體學習下Optional:

創(chuàng)建Optional

創(chuàng)建一個Optional對象有好幾種方式:

  1. 創(chuàng)建一個空的Optional
    我們可以使用靜態(tài)工廠方法Optional.empty,創(chuàng)建一個空的Optional對象:
Optional<Department> department = Optional.empty();
  1. 根據(jù)非空值創(chuàng)建Optional
    我們也可以使用靜態(tài)工廠方法Optional.of來創(chuàng)建一個非空對象的Optional對象:
Optional<Employee> optEmployee = Optional.of(employee);

如果employee為空,這段代碼會立即拋出一個NullPointerException。

  1. 創(chuàng)建可以為null的Optional
    使用靜態(tài)工廠方法Optional.ofNullable,我們可以創(chuàng)建一個允許null值的Optional對象:
Optional<Employee> optEmployee = Optional.ofNullable(employee);

如果employee為空,對其調用get方法將拋出NoSuchElementException。

Optional方法

Optional類包含了許多方法,下面介紹這些方法的使用。

  1. isPresent
    顧名思義,如果值存在返回true,否則返回false。如:
 Optional<Department> opt = Optional.ofNullable(department);
if(opt.isPresent()){
    System.out.println(opt.get().getEmployee());
}
  1. get
    如果Optional有值則將其返回,否則拋出NoSuchElementException。下面舉個拋出NoSuchElementException的例子:
try {
    Optional.empty().get();
} catch (Exception e) {
    e.printStackTrace();
}

代碼將捕獲到 java.util.NoSuchElementException: No value present 異常。

  1. ifPresent
    如果Optional實例有值則為其調用Consumer(函數(shù)描述符為T -> void),否則不做處理。如:
girl.ifPresent(g -> System.out.println("我有女朋友,名字是:" + g.getName()));
  1. orElse
    如果Optional實例有值則將其返回,否則返回orElse方法傳入的參數(shù)。如:
System.out.println(Optional.empty().orElse("There is no value present!"));

程序將輸出There is no value present!。

  1. orElseGet
    orElseGet與orElse方法類似,orElse方法將傳入的字符串作為默認值,而orElseGet方法可以接受Supplier(函數(shù)描述符為() -> T)來生成默認值。如:
System.out.println(Optional.empty().orElseGet(() -> "There is no value present!"));

程序同樣輸出There is no value present!。

  1. orElseThrow
    如果有值則將其返回,否則拋出Supplier接口創(chuàng)建的異常。如:
try {
    Optional.empty().orElseThrow(NoSuchElementException::new);
} catch (Exception e) {
    e.printStackTrace();
}

代碼將捕獲到 java.util.NoSuchElementException: No value present 異常。
7.map
如果Optional有值,則對其執(zhí)行調用Function函數(shù)描述符為(T -> R)得到返回值。如果返回值不為null,則創(chuàng)建包含F(xiàn)unction回值的Optional作為map方法返回值,否則返回空Optional。

Optional<String> upperName = name.map(String::toUpperCase);
System.out.println(upperName.orElse("No value found"));
  1. flatMap
    如果有值,為其執(zhí)行Function函數(shù)返回Optional類型返回值,否則返回空Optional。flatMap與map方法類似,區(qū)別在于flatMap中的Function函數(shù)返回值必須是Optional。調用結束時,flatMap不會對結果用Optional封裝。如:
upperName = name.flatMap((value) -> Optional.of(value.toUpperCase()));
System.out.println(upperName.orElse("No value found"));
  1. filter
    filter個方法通過傳入Predicate(函數(shù)描述符為T -> Boolean)對Optional實例的值進行過濾。如:
Optional<String> name = Optional.of("Jane");
Optional<String> LongName = name.filter((value) -> value.length() >= 3);
System.out.println(LongName.orElse("名字長度小于3個字符"));

方法輸出Jane。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容