Java8的新特性–Optional

Optional

一、Optional類是什麼?

Optional 類(java.util.Optional)是一個容器類,代表一個值存在或不存在,原來用null表示一個值不存在,現在用Optional可以更好的表達這個概念。並且可以避免空指針。

二、Optional類常用的方法

1. 創建Optional實例

這個類型的對象可能包含值,也可能為空。

1.1 Optional.of(T)

創建一個Optional實例

    @Test
    public void test01(){
        ////創建一個帶泛型的Optional容器類
        Optional<Employee> employee = Optional.of(new Employee());
        System.out.println(employee.get());

        //會報空指針異常
        Optional<Employee> employee1 = Optional.of(null);
        System.out.println(employee1.get());

    }
}

這裡我們需要注意,Optional.of(null),of方法傳null時,會報NullPointException.

1.2 Optional.empty()

創建一個空的Optional實例

    @Test
    public void test02(){
        //構建了一個空的Optional實例,裡面沒有任何東西
        Optional<Employee> employee = Optional.empty();
        System.out.println(employee.get());//輸出 java.util.NoSuchElementException: No value present
    }

1.3. Optional.ofNullable(T t)

Optional類中的of()方法不允許包裝null,但是ofNullable()方法可以,傳遞到該方法中的若為null,則構建一個空的Optional實例

    @Test
    public void test03(){
        //不會報空指針異常
        //Optional類中的of()方法不允許包裝null,但是ofNullable()方法可以,傳遞到該方法中的若為null,則構建一個空的Optional實例
        Optional<Employee> employee2 = Optional.ofNullable(null);
        if(employee2.isPresent()){
            System.out.println(employee2.get());
        }else{
            System.out.println("------------");
        }
    }

我們來看一下ofNullable源碼

    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

即如果傳進來的是null則直接調用了empty(),不為null時才調用of(value)。

1.4. 小結

這個類型的對象可能包含值,也可能為空。我們可以使用Optional.empty()方法創建一個空的Optional,也可以使用of() 和 ofNullable() 方法創建包含值的 Optional。這倆方法的不同之處在於如果把null值作為參數傳遞進去,of()方法會拋出NullPointerException。所以,我們應該在對象不為 null的時候使用 of(),對象即可能是 null 也可能是非null,使用 ofNullable() 方法。

2.訪問Optional對象的值

2.1 get()獲取值

    @Test
    public void test01(){
        ////創建一個帶泛型的Optional容器類
        Optional<Employee> employee = Optional.of(new Employee());
        //獲取值
        System.out.println(employee.get());
    }

從 Optional 實例中取回實際值對象的方法之一是使用 get() 方法。不過,這個方法會在值為null的時候拋出異常,為了避免我們要先驗證是否有值。

2.2 isPresent()驗證是否有值

    @Test
    public void test03(){
        //不會報空指針異常
        //Optional類中的of()方法不允許包裝null,但是ofNullable()方法可以,傳遞到該方法中的若為null,則構建一個空的Optional實例
        Optional<Employee> employee2 = Optional.ofNullable(null);
        //判斷是否存在
        if(employee2.isPresent()){//存在
            System.out.println(employee2.get());
        }else{//不存在
            System.out.println("------------");
        }
    }

2.3 ifPresent()

檢查是否有值的時候還可以用ifPresent(),該方法除了執行檢查,還可以接受一個Consumer(消費者)參數,如果對象不是空的,就執行傳入的Lambda表達式。

    @Test
    public void test04(){
        Optional<Employee> employee2 = Optional.ofNullable(new Employee());
        //如果對象不是空的,就執行傳入的Lambda表達式。
        employee2.ifPresent(e -> System.out.println(e.getAge()));
    }

3. 返回默認值

Optional類提供API用以返回對象值,或者在對象為空的時候返回默認值。

3.1 orElse(T t)

如果調用對象包含有值,那麼返回該值,否則返回orElse()方法中的對象。

    @Test
    public void test05(){
        Optional<Employee> op = Optional.ofNullable(new Employee());
        Employee em = op.orElse(new Employee("默認姓名", 20, 1000));
        System.out.println(em);//列印Employee{name='null', age=0, salary=0.0}

        Optional<Employee> op1 = Optional.ofNullable(null);
        Employee em1 = op1.orElse(new Employee("默認姓名", 20, 1000));
        System.out.println(em1);//列印Employee{name='默認姓名', age=20, salary=1000.0}
    }

3.2 orElseGet(Supplier s)

    @Test
    public void test06(){
        Optional<Employee> op = Optional.ofNullable(new Employee());
        Employee em = op.orElseGet(() -> new Employee("默認姓名", 20, 1000));
        System.out.println(em);//列印Employee{name='null', age=0, salary=0.0}

        Optional<Employee> op1 = Optional.ofNullable(null);
        Employee em1 = op1.orElseGet(() -> new Employee("默認姓名", 20, 1000));
        System.out.println(em1);//列印Employee{name='默認姓名', age=20, salary=1000.0}
    }

3.3 orElse(T t)和orElseGet(Supplier s)的不同

先來看看傳入對象都為null時


    public Employee createNewEmployee(){
        System.out.println("==========創建一個新對象====");
        return new Employee("默認姓名1", 20, 1000);
    }
    
    @Test
    public void test07(){

        //傳入對象都為null時
        Employee e = null;
        Optional<Employee> op = Optional.ofNullable(e);
        System.out.println("-----orElse----");
        Employee em = op.orElse(createNewEmployee());
        System.out.println("-----orElseGet----");
        Employee em1 = op.orElseGet(() -> createNewEmployee());
    }

運行結果:兩種方法都調用了 createNewEmployee() 方法


-----orElse----
==========創建一個新對象====
-----orElseGet----
==========創建一個新對象====
    //不同之處
    @Test
    public void test08(){
        //傳入對象都不為null時
        Employee e = new Employee("默認姓名", 20, 1000);
        Optional<Employee> op = Optional.ofNullable(e);
        System.out.println("-----orElse----");
        Employee em = op.orElse(createNewEmployee());
        System.out.println("-----orElseGet----");
        Employee em1 = op.orElseGet(() -> createNewEmployee());
    }

運行結果,只有一個方法調用了createNewEmployee()

-----orElse----
==========創建一個新對象====
-----orElseGet----

這個例子說明,兩個 Optional 對象都包含非空值,兩個方法都會返回對應的非空值。不過,orElse() 方法仍然創建了 User 對象。與之相反,orElseGet() 方法不創建 User 對象。

在執行較密集的調用時,比如調用 Web 服務或數據查詢,這個差異會對性能產生重大影響。

4. 轉換值

4.1 map(Function f)

若有值則對其處理,並返回處理後的Optional,否則返回Optional.empty()。

    @Test
    public void test09(){

        String str = Optional.ofNullable(new Employee())
                .map(Employee::getName).orElse("張三");
        System.out.println(str);//列印輸出張三
        Employee e = new Employee("默認姓名", 20, 1000);
        String str2 = Optional.ofNullable(e)
                .map(Employee::getName).orElse("張三");
        System.out.println(str2);//列印輸出默認姓名

    }

4.2 flatMap(Function mapper)

與map類似,但要求返回值必須是Optional。

    @Test
    public void test10(){
        Employee em = new Employee("默認姓名", 20, 1000);

        //map
        Optional<String> s1 = Optional.ofNullable(em)
                .map(Employee::getName);
        System.out.println(s1);
        //flatMap  要求返回的是Optional  避免空指針
        Optional<String> s2 = Optional.ofNullable(em)
                .flatMap(e -> Optional.of(e.getName()));
        System.out.println(s2);

    }

5. 過濾值

除了轉換值之外,Optional 類也提供了按條件「過濾」值的方法。

5.1 filter()

filter() 接收一個Predicate參數,返回測試結果為true的值,如果測試結果為false,會返回一個空的Optional。

    @Test
    public void test11(){

        //map
        Optional<Employee> employee = Optional.ofNullable(new Employee())
                .filter(e -> e.getName() != null);
        System.out.println(employee);//返回一個空的Optional  Optional.empty
        Employee em = new Employee("默認姓名", 20, 1000);

        Optional<Employee> employee1 = Optional.ofNullable(em)
                .filter(e -> e.getName() != null);
        System.out.println(employee1);//Optional[Employee{name='默認姓名', age=20, salary=1000.0}]

    }

如果通過過濾器測試,result 對象會包含非空值。

三、總結

Optional類其實就是一個封裝了一個元素的容器,而這個元素可以是null也可以是其它任意類型的。Optional是Java語言的有益補充,它旨在減少程式碼中的NullPointerExceptions,雖然不能完全消除這些異常,他也是精心設計,自然融入了Java8函數式支援的功能

Tags: