Java 8新增的類-Optional
Optional作用
Java8中新增了Optional類,Optional類相當於一個容器,這個容器可以包含一個null,也可以包含任何非null的對象。
這個類有兩個作用(目的):
- 消除代碼中的NullPointerExecption
- 處理對象爲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()
返回名字列表。如果list
爲null
,則創建一個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注意事項
使用這個類需要注意以下幾點:
- Optional不能作爲字段或方法參數的類型,這個類只是一個工具類
- Optional 類型不可被序列化, 用作字段類型會出問題的
- Optional中的value是隻讀的,Optional沒有提供API來修改value
- 調用Optional.get()之前,可以不用事先使用isPresent()方法檢查當前Optional包含的value是否可用。因爲Optional中的value==null時,get()方法會拋出異常
- 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();
}
}