摘要
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