Java 8新增的類-Optional

Java 8新增的類-Optional

Optional作用

Java8中新增了Optional類,Optional類相當於一個容器,這個容器可以包含一個null,也可以包含任何非null的對象。
這個類有兩個作用(目的):

  1. 消除代碼中的NullPointerExecption
  2. 處理對象爲null,不爲空的情況下的代碼變得更加優雅和簡潔

按照功能分類Optional類的API

Optional類的Api按照功能,可分爲以下幾類:
創建Optional實例的api,包括empty()of()ofNullable(),返回的是一個Optional實例
Optaional中的value爲null時,做什麼的api,包括orElse()orElseGet()orElseThrow(),返回值是Optional中的vlaue
Optaional中的value不爲null時,做什麼的api,包括ifPresent()map()flatMap(),其中ifPresent()不返回任何值,map()flatMap()返回一個新的Optional對象
其它分類get()isPresent()filter()

Optional在實際中的應用

getListName()返回名字列表。如果listnull,則創建一個empty list返回,否則就返回list。使用了Optioanal中的orElse()方法來替代傳統的if..else..,讓代碼看起來更加簡潔。

    /**
     * 返回名字列表
     *
     * @return
     */
    @Test
    public List<String> getListName() {
        /*Java8之前的寫法*/
        /*        
        List<String> list = null;
        if (list == null) {
            return Collections.emptyList();
        } else {
            return list;
        }
        */

        /*Java8 Optional寫法*/
        List<String> list = null;
        return Optional.of(list).orElse(Collections.emptyList());
    }

nameFormatDemo()名字首字母大寫,如果name!=null則首字母轉換爲大寫,如果name==null,則賦予no name值。

/**
     * 名字首字母大寫
     */
    @Test
    public void nameFormatDemo() {
        final String DEFAULT_NAME = "no name";
        /*Java8之前的寫法*/
        String name = "tom";
        if (name != null) {
            name = name.substring(0, 1).toUpperCase() + name.substring(1, name.length());
        }else{
            name = DEFAULT_NAME;
        }
        System.out.println(String.format("Java8之前的寫法,name:%s", name));

        /*Java8 Optional寫法*/
        name = "tom";
        //name = null;
        Optional<String> nameOptional = Optional.ofNullable(name);
        name =  nameOptional.map(value -> value.substring(0, 1).toUpperCase() + value.substring(1, value.length())).orElse(DEFAULT_NAME);
        System.out.println(String.format("Java8 Optional寫法,name:%s", name));
    }

printName()打印名字到控制檯。name!=null則打印name到控制檯,否則什麼也不做。ifPresent()的作用是Optional中的value爲null時,執行傳遞函數,否則什麼也不做。

      /**
     * 打印名字到控制檯
     */
    @Test
    public void printName(){
        String name = "Tom";
        /*Java8之前的寫法*/
        if (name != null) {
            System.out.println(String.format("name:%s",name));
        }
        
        /*Java8 Optional寫法*/
        Optional.ofNullable(name).ifPresent(value -> System.out.println(String.format("name:%s",value)));
    }

使用Optional注意事項

使用這個類需要注意以下幾點:

  1. Optional不能作爲字段或方法參數的類型,這個類只是一個工具類
  2. Optional 類型不可被序列化, 用作字段類型會出問題的
  3. Optional中的value是隻讀的,Optional沒有提供API來修改value
  4. 調用Optional.get()之前,可以不用事先使用isPresent()方法檢查當前Optional包含的value是否可用。因爲Optional中的value==null時,get()方法會拋出異常
  5. Optional類沒有什麼難點,多看幾遍源碼就懂了

Optional使用示例

package com.zhangxy.optional;

import org.junit.jupiter.api.Test;
import org.junit.platform.commons.util.ToStringBuilder;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * Java8中新增了Optional類
 * Optional類相當於一個容器,這個容器可以包含一個null,也可以包含任何非null的對象
 * 這個類誕生的目的有兩個:1. 消除代碼中的NullPointerExecption 2. 處理對象爲null,不爲空的情況下的代碼變得更加優雅和簡潔
 * @author zhangxy
 * @credte 2020-06-16 20:46
 */
public class OptionalTest {

    @Test
    public void emptyDemo() {
        Optional<Object> empty = Optional.empty();
        System.out.println(empty);//=>Optional.empty
    }

    /**
     * of(T value):用於給Optional<T>實例中的value屬性賦值,如果傳遞的vlaue==null將會拋出NullPointerException
     */
    @Test
    public void foDemo() {
        Optional<String> optional = Optional.of("小明");
        System.out.println("optional toString:" + optional);//=>myName is present:Optional[小明]

        Optional<String> nullOptional = Optional.of(null);//=>throw java.lang.NullPointerException
    }

    /**
     * ofNullabel(T value):作用同of(T value)相同,不同的是,如果傳遞的value==null不會拋出任何異常,返回一個empty的Optional實例
     */
    @Test
    public void ofNullable() {
        Optional<String> optional = Optional.ofNullable("小明");
        System.out.println("optional toString:" + optional);//=>myName is present:Optional[小明]

        Optional<String> nullOptional = Optional.ofNullable(null);
        System.out.println("optional toString:" + nullOptional);//=>optional toString:Optional.empty
    }

    /**
     * get():獲取Optional實例中的value,如果vlaue==null,會拋出java.util.NoSuchElementException: No value present異常
     */
    @Test
    public void getDeom() {
        Optional<String> optional = Optional.of("小明");
        String myName = optional.get();
        System.out.println(String.format("myName:%s", myName));//=>myName:小明

        optional = Optional.empty();
        myName = optional.get();
        System.out.println(String.format("myName:%s", myName));//=>java.util.NoSuchElementException: No value present
    }

    /**
     * isPresent():用於判斷Optional<T>實例中value值是否爲null,true表示不爲null,否則爲null
     */
    @Test
    public void isPresentDemo() {
        Optional<String> myName = Optional.empty();
        System.out.println("myName is present:" + myName.isPresent());//=>false

        myName = Optional.of("zhangxy");
        System.out.println("myName is present:" + myName.isPresent());//=>true

        myName = Optional.ofNullable(null);
        System.out.println("myName is present:" + myName.isPresent());//=>false
    }

    /**
     * ifPresent():如果Optional實例的vlaue!=null,則執行Consumer實例的accept(),否則什麼也不執行
     * 相當於:
     * if(value!=null){
     *      //做一些操作,尤其是這些操作的代碼較多時,這樣寫會顯得代碼更簡潔寫
     * }else{
     *      //什麼也不做
     * }
     */
    @Test
    public void ifPresentDemo() {
        Optional<String> optional = Optional.of("ABC");
        optional.ifPresent(value -> System.out.println(String.format("value:%s", value)));//=>value:ABC

        optional = Optional.empty();
        optional.ifPresent(value -> System.out.println(String.format("value:%s", value)));//什麼也不輸出
    }

    /**
     * filter(Predicate<? super T> predicate):根據Predicate實例的test()返回的值爲true則返回當前Optional對象,否則返回一個empty的Optional對象
     * 相當於,滿足過濾條件返回當前Optional對象,否則返回empty的Optional對象
     */
    @Test
    public void filterDemo() {
        Optional<String> optional = Optional.of("ABC").filter(value -> value.contains("A"));
        System.out.println(optional);//=>Optional[ABC]

        optional = Optional.of("ABC").filter(value -> value.contains("a"));
        System.out.println(optional);//=>Optional.empty
    }

    /**
     * map(Function mapper):如果isPresent()==true,則調用Function實例的apply(value)對value進行相關邏輯操作,然後返回一個新的Optional對象,否則返回一個empty的Optional對象
     * 相當於:
     * if(value!=null){
     *      //對value進行邏輯操作
     *      //產生了一個newValue
     *      //return new Optional<NewValue>,返回一個value類型爲NewValue的Optional對象
     * }else{
     *      //return Optional.empty(),返回一個空的Optional對象
     * }
     */
    @Test
    public void mapDemo() {
        Optional<UserInfo> userInfoOptional = Optional.of("zhangxy~25").map(value -> {
            String[] array = value.split("~");
            return new UserInfo(array[0], Integer.parseInt(array[1]));
        });

        System.out.println(userInfoOptional);
    }

    /**
     * flatMap(Function mapper):和map(Function mapper)作用相同
     * 不同的是Function實例的apply()方法如果返回null,將會拋出NullPointerExecption
     * 不同的是Function實例的apply()方法如需要顯示的返回一個Optional對象
     */
    @Test
    public void flatMapDemo() {
        Optional<UserInfo> userInfoOptional = Optional.of("zhangxy~25").flatMap(value -> {
            String[] array = value.split("~");
            //return Optional.of(new UserInfo(array[0], Integer.parseInt(array[1])));
            return null;
        });

        System.out.println(userInfoOptional);
    }

    /**
     * orElse(T t):Optional實例的value==null,則返回t(即傳入的值),否則返回Optional實例的value
     * 相當於:
     * if(value==null){
     *      return t;
     * }else{
     *      reutrn value;
     * }
     */
    @Test
    public void orElseDemo() {
        Optional<String> optional = Optional.of("小明");
        System.out.println(optional.orElse("小李"));

        optional = Optional.empty();
        System.out.println(optional.orElse("小李"));
    }

    /**
     * orElseGet(Supplier other):作用和orElse(T t)類似
     * Optional實例的value==null,則返回Supplier實例的get()方法返回值,否則返回Optional實例的value
     * 相當於:
     * if(value==null){
     *      return get();
     * }else{
     *      reutrn value;
     * }
     */
    @Test
    public void orElseGetDemo() {
        Optional<String> optional = Optional.of("小明");
        System.out.println(optional.orElse("小李"));

        optional = Optional.empty();
        System.out.println(optional.orElseGet(() -> {
            return "小李";
        }));
    }

    /**
     * orElseThrow():作用和orElse(T t)類似
     * Optional實例的value==null,則爬出Supplier實例的get()方法返回的異常,否則返回Optional實例的value
     * 相當於:
     * if(value==null){
     *     throw get();
     * }else{
     *     return value;
     * }
     * @throws Exception
     */
    @Test
    public void orElseThrowDeom() throws Exception {
        Optional<String> optional = Optional.of("小明");
        optional.orElseThrow(() -> {
            return new Exception("測試異常");
        });

        optional = optional = Optional.empty();
        optional.orElseThrow(() -> {
            return new Exception("測試異常");
        });
    }

    /**
     * 返回名字列表
     *
     * @return
     */
    @Test
    public List<String> getListName() {
        /*Java8之前的寫法*/
        /*
        List<String> list = null;
        if (list == null) {
            return Collections.emptyList();
        } else {
            return list;
        }
        */

        /*Java8 Optional寫法*/
        List<String> list = null;
        return Optional.of(list).orElse(Collections.emptyList());
    }

    /**
     * 打印名字到控制檯
     */
    @Test
    public void printName(){
        String name = "Tom";
        /*Java8之前的寫法*/
        if (name != null) {
            System.out.println(String.format("name:%s",name));
        }

        /*Java8 Optional寫法*/
        Optional.ofNullable(name).ifPresent(value -> System.out.println(String.format("name:%s",value)));
    }

    /**
     * 名字首字母大寫
     */
    @Test
    public void nameFormatDemo() {
        final String DEFAULT_NAME = "no name";
        /*Java8之前的寫法*/
        String name = "tom";
        if (name != null) {
            name = name.substring(0, 1).toUpperCase() + name.substring(1, name.length());
        }else{
            name = DEFAULT_NAME;
        }
        System.out.println(String.format("Java8之前的寫法,name:%s", name));

        /*Java8 Optional寫法*/
        name = "tom";
        //name = null;
        Optional<String> nameOptional = Optional.ofNullable(name);
        name =  nameOptional.map(value -> value.substring(0, 1).toUpperCase() + value.substring(1, value.length())).orElse(DEFAULT_NAME);

        System.out.println(String.format("Java8 Optional寫法,name:%s", name));
    }
}

class UserInfo implements Serializable {
    private String name;
    private Integer age;

    public UserInfo(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this)
                .append("name", name)
                .append("age", age)
                .toString();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章