JAVA8之工具類Optional
一. 概述
Optional類并不像之前介紹的工具都是借口,他是一個被final修飾的具體的類,我們一般拿它做一些對空(null)的判定.基本提供的都是靜态方法,可以之間用.方法名調用.先看其源碼:
package java.util;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
private Optional() {
this.value = null;
}
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
public boolean isPresent() {
return value != null;
}
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}
public T orElse(T other) {
return value != null ? value : other;
}
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Optional)) {
return false;
}
Optional<?> other = (Optional<?>) obj;
return Objects.equals(value, other.value);
}
@Override
public int hashCode() {
return Objects.hashCode(value);
}
@Override
public String toString() {
return value != null
? String.format("Optional[%s]", value)
: "Optional.empty";
}
}
這麼多方法是不是驚呆了.首先先從 構造方法講起.
1. empty方法(私有)
沒有入參,直接new出一個Optional執行個體傳回.
2. of方法
接受一個傳入類型構造一個包含傳入值的Optional執行個體傳回,該方法并沒有對入參做非空判定,如果傳入的參數是null的話,直接就會抛出異常,可用來阻擋null值的傳入.
3. ofNullable方法
看名字就知道,在傳入參數的時候,對入參做了非空判定,如果傳入的參數是null的話,就會new出來一個新的Optional執行個體.如果不是null,則構造一個包含傳入值的Optional執行個體傳回.
下面講解其他方法.
4. isPresent方法
沒有入參,傳回一個布爾值(boolean).判斷調用方法的對象是否為空,為空則傳回false,非空則傳回true.如同object != null的傳回結果.
5. get方法
如果Optional中有值,則傳回該值,如果沒有,則抛出NoSuchElementException的異常.
6. ifPresent方法
如果Optional中有值,則進行下面的操作,如果為空,則什麼也不做.
7. orElse方法
接受一個傳入類型,如果Optional中有值,則傳回該值,如果為空,則傳回預設值
8. orElseGet方法
接受一個Supplier類型的資料,如果Optional中有值,則傳回該值,如果為空,則傳回一個Supllier生成的一個資料.
9. orElseThrow方法
同第8個方法,隻是在為空的時候,抛出一個由Supplier生成的指定異常.
10. filter方法
顧名思義,這是一個過濾方法.傳入一個Predicate類型的參數,如果滿足Predicate條件,則傳回該Optional的值,反之則傳回一個空的Optional對象.
11. map方法
如果Optional的值存在,則進行傳入的Function接口的方法,并傳回其方法結束後的值,并封裝成一個Optional的對象,否則傳回一個空的Optional對象.
12. flatMap方法
如同第11方法,但是其傳回值必須是一個Optianal類型的對象.
二. 示例
方法較多,我們寫幾個常用示例,先建立一個使用者實體類,有姓名和年齡參數,getter,setter方法,并重寫了toString方法友善列印結果:
package com.yczuoxin.demo.optional;
public class User {
private String name;
private Integer age;
public User() {
}
public User(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 "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
1. 傳入一個對象,如果是空我們不做任何操作,如果不是空,就講對象列印出來.
package com.yczuoxin.demo.optional;
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
Optional<User> user = Optional.ofNullable(new User("張三",18));
Optional<User> empty = Optional.ofNullable(null);
user.ifPresent(existUser -> System.out.println(existUser));
}
}
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNvwVZ2x2bzNXak9CX90TQNNkRrFlQKBTSvwFbslmZvwFMwQzLcVmepNHdu9mZvwFVywUNMZTY18CX052bm9CX90zZiBHazIWMwhUZqx2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2LcRHelR3LcJzLctmch1mclRXY39DO4kDO0QDM3EDNxcDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
測試成功,隻列印出了非空的結果.注意,此處如果用of代替ofNullable的話會直接抛出異常.
2. 傳入一個字元串,如果是空,則傳回empty string, 如果不是空則傳回其值.
package com.yczuoxin.demo.optional;
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
Optional<String> str = Optional.ofNullable("string");
Optional<String> empty = Optional.ofNullable(null);
System.out.println(str.orElse("new string"));
System.out.println(empty.orElse("empty string"));
}
}
也可以使用另一個方法
package com.yczuoxin.demo.optional;
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
Optional<String> str = Optional.ofNullable("string");
Optional<String> empty = Optional.ofNullable(null);
System.out.println(str.orElseGet(() -> new String("is empty")));
System.out.println(empty.orElseGet(() -> new String("is empty")));
}
}
測試成功.
3. 傳入一個使用者,如果使用者存在,則擷取使用者的使用者名,并将其使用者名的字母全部大寫輸出.
package com.yczuoxin.demo.optional;
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
User user = new User("zhangsan",18);
User empty = null;
System.out.println(Optional.ofNullable(user).map(user1 -> user1.getName()).map(name -> name.toUpperCase()));
System.out.println(Optional.ofNullable(empty).map(user1 -> user1.getName()).map(name -> name.toUpperCase()));
}
}
測試成功.可以看見,如果使用of方法,會報出空指針異常.
4. 年齡大于20的使用者則輸出其使用者名.
package com.yczuoxin.demo.optional;
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
User zhangsan = new User("zhangsan",18);
User lisi = new User("lisi",21);
Optional<String> zhangsanName = Optional.ofNullable(zhangsan).filter(user -> user.getAge() > 20)
.map(user -> user.getName());
System.out.println(zhangsanName);
Optional<String> lisiName = Optional.ofNullable(lisi).filter(user -> user.getAge() > 20)
.map(user -> user.getName());
System.out.println(lisiName);
}
}
測試成功.輸出了年齡大于20的使用者的姓名.
三. 總結
這個工具類被用作對空的判定.該工具類有幾個使用限制:
1. 單純使用isPresent方法和get方法跟我們之前的寫法并沒有什麼減少代碼書寫的工作量,反而還增加了對Optional的封裝.
2. Optional類沒有實作Serializable的接口,是以不能被序列化,即不能作為類的屬性或者方法入參.