Java8的新特性–Optional
Optional
一、Optional類是什麼?
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函數式支援的功能