jdk8新特性-Optional

摘要

Optional 類主要解決的問題是臭名昭著的空指針異常(NullPointerException)。它提供了可設置爲空值(ofNullable)、值是否存在(isPresent)、值爲空時取默認值(orElse)等方法,讓我們在操作對象時可以優雅處理空值。


示例

1.empty()

通過empty創建一個空的Optional,此時get時會報錯

2.get()

get()方法獲取Optional值,如果爲空時會報java.util.NoSuchElementException: No value present

System.out.println("-----Optional.empty-----");
Optional<String> optional=Optional.empty();
optional.get();

輸出

-----Optional.empty-----
java.util.NoSuchElementException: No value present

3.of()

of()向Optional填充值,此時不能爲空,爲空時報錯

System.out.println("-----Optional.off-----");
User emptyUser=null;
Optional<User> optional = Optional.of(emptyUser);

輸出

-----Optional.off-----
java.lang.NullPointerException

4.ofNullable()

ofNullable()向Optional填充值,此時可爲空

System.out.println("-----Optional.ofNullable-----");
User emptyUser=null;
Optional.ofNullable(emptyUser);

5.isPresent()

判斷Optional值是否存在

System.out.println("-----Optional.isPresent-----");
Optional<String> optional= Optional.empty();
 System.out.println(optional.isPresent());

輸出

-----Optional.isPresent-----
false

該方法除了執行檢查,還接受一個Consumer(消費者) 參數,如果對象不是空的,就對執行傳入的 Lambda 表達式:

System.out.println("-----Optional.isPresentLambda-----");
User user=new User(1,"小楊");
Optional<User> optional= Optional.of(user);
optional.ifPresent( u -> System.out.println("用戶名:"+u.getName()));

輸出

-----Optional.isPresentLambda-----
用戶名:小楊

6.orElse()

orElse()如果有值則返回該值,否則返回傳遞給它的參數值

System.out.println("-----Optional.orElse-----");
User emptyUser=null;
User user=new User(1,"小楊");
User res= Optional.ofNullable(emptyUser).orElse(user);
System.out.println(toString(res));

輸出

-----Optional.orElse-----
{“id”:1,“name”:“小楊”}

7.orElseGet()

有值的時候返回值,如果沒有值,它會執行作爲參數傳入的 Supplier(供應者) 函數式接口,並將返回其執行結果。

@Test
public void orElseGet(){
    System.out.println("-----Optional.orElseGet-----");
    User emptyUser=null;
    User res= Optional.ofNullable(emptyUser).orElseGet(()->getDefaultUser());
    System.out.println(toString(res));
}
private User getDefaultUser(){
    System.out.println("創建默認用戶");
    User user=new User(0,"管理員");
    return user;
}

輸出

-----Optional.orElseGet-----
創建默認用戶
{“id”:0,“name”:“管理員”}

orElse()與orElseGet()在值爲空時沒有區別,但是在有值時orElse仍然會運行創建orElse()中的對象

@Test
public void orElseGetAndOrElse(){
    System.out.println("-----Optional.orElseGetAndOrElse-----");
    User defUser=new User(1,"小楊");
    System.out.println("Optional.orElse");
    User user = Optional.ofNullable(defUser).orElse(getDefaultUser());
    System.out.println(toString(user));
    System.out.println("Optional.orElseGet");
    User res= Optional.ofNullable(defUser).orElseGet(()->getDefaultUser());
    System.out.println(toString(res));
}

private User getDefaultUser(){
    System.out.println("創建默認用戶");
    User user=new User(0,"管理員");
    return user;
}

輸出

-----Optional.orElseGetAndOrElse-----
Optional.orElse
創建默認用戶
{“id”:1,“name”:“小楊”}
Optional.orElseGet
{“id”:1,“name”:“小楊”}

8.orElseThrow()

對象爲空的時候拋出異常

System.out.println("-----Optional.orElseThrow-----");
String res = (String)Optional.empty().orElseThrow( () -> new IllegalArgumentException("值爲空"));

輸出

-----Optional.orElseThrow-----
java.lang.IllegalArgumentException: 值爲空

9.map()

對值調用作爲參數的函數,然後將返回的值包裝在 Optional 中。

System.out.println("-----Optional.map-----");
User user=new User(1,"小楊");
String userName=Optional.ofNullable(user).map(u->u.getName()).get();
System.out.println(userName);

輸出

-----Optional.map-----
小楊

10.filter()

返回過濾結果爲 true 的值。如果測試結果爲 false,會返回一個空的 Optional

System.out.println("-----Optional.filter-----");
System.out.println("-----name=小楊-----");
User user=new User(1,"小楊");
String res=Optional.ofNullable(user).filter(u->u.getName().equals("小楊")).map(u->u.getName()).orElse("用戶不存在");
System.out.println(toString(res));
System.out.println("-----name=小張-----");
String res1=Optional.ofNullable(user).filter(u->u.getName().equals("小張")).map(u->u.getName()).orElse("用戶不存在");
System.out.println(toString(res1));

輸出

-----Optional.filter-----
-----name=小楊-----
“小楊”
-----name=小張-----
“用戶不存在”


優雅處理NPE

1.傳統NPE處理

private static String defaultPreUrl="http://127.0.0.1/preview/miss.jpg";
private static FileV1 file1=new FileV1(1,"測試文件",null,"http://127.0.0.1/file/test.pdf");
private static ResourceV1 resource1 = new ResourceV1(1,"測試資源",file1);
@Test
public void NPEV1(){
   System.out.println("-----------傳統NPE判斷-----------");
   String url=defaultPreUrl;
   if (file1 != null) {
       FileV1 file = resource1.getFile();
       if (file != null) {
           PreviewV1 preview = file.getPreview();
           if (preview != null) {
               url = preview.getUrl();
           }
       }
   }
   System.out.println(url);
}
class ResourceV1{
    private Integer id;
    private String name;
    private FileV1 file;
    public ResourceV1(Integer id, String name, FileV1 file) {
        this.id = id;
        this.name = name;
        this.file = file;
    }
	//get set
}

class FileV1{
    private Integer id;
    private String name;
    private PreviewV1 preview;
    private String url;
    public FileV1(Integer id, String name, PreviewV1 preview, String url) {
        this.id = id;
        this.name = name;
        this.preview = preview;
        this.url = url;
    }
	//get set
}

class PreviewV1{
    private Integer id;
    private String name;
    private String url;
    public PreviewV1(Integer id, String name, String url) {
        this.id = id;
        this.name = name;
        this.url = url;
    }
	//get set
}

輸出

-----------傳統NPE判斷-----------
http://127.0.0.1/preview/miss.jpg

2.通過Optional處理NPE

private static String defaultPreUrl="http://127.0.0.1/preview/miss.jpg";
private static FileV2 file2=new FileV2(1,"測試文件",null,"http://127.0.0.1/file/test.pdf");
private static ResourceV2 resource2 = new ResourceV2(1,"測試資源",file2);
@Test
public void NPEV2(){
   System.out.println("-----------Optional NPE判斷-----------");
   String result = Optional.ofNullable(resource2)
           .flatMap(ResourceV2::getFile)
           .flatMap(FileV2::getPreview)
           .map(PreviewV2::getUrl)
           .orElse(Optional.of(defaultPreUrl)).get();
   System.out.println(result);
}
class ResourceV2{
    private Integer id;
    private String name;
    private FileV2 file;
    public ResourceV2(Integer id, String name, FileV2 file) {
        this.id = id;
        this.name = name;
        this.file = file;
    }
    public Optional<FileV2> getFile() {
        return Optional.ofNullable(file);
    }
    public void setFile(FileV2 file) {
        this.file = file;
    }
    //get set
}

class FileV2{
    private Integer id;
    private String name;
    private PreviewV2 preview;
    private String url;
    public FileV2(Integer id, String name, PreviewV2 previewV2, String url) {
        this.id = id;
        this.name = name;
        this.preview = preview;
        this.url = url;
    }
    public Optional<PreviewV2> getPreview() {
        return Optional.ofNullable(preview);
    }
    public void setPreview(PreviewV2 preview) {
        this.preview = preview;
    }
	//get set
}

class PreviewV2{
    private Integer id;
    private String name;
    private String url;
    public PreviewV2(Integer id, String name, String url) {
        this.id = id;
        this.name = name;
        this.url = url;
    }
    public Optional<String> getUrl() {
        return Optional.ofNullable(url);
    }
    public void setUrl(String url) {
        this.url = url;
    }
    //get set
}

輸出

-----------Optional NPE判斷-----------
http://127.0.0.1/preview/miss.jpg

發佈了36 篇原創文章 · 獲贊 28 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章