天天看點

Optional 接口初使用

Optional 接口

源碼

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";
    }
}      

有時候看看源碼也是一種享受啊,學習源碼的這種編碼方式,讓我受益匪淺。

接下來,說說 Optional 接口的方法:

構造方法

構造一個 value 屬性為 null 的 Optional 執行個體

private Optional() {
        this.value = null;
}      

構造一個 value 屬性不為 null 的 Optional 執行個體,如果傳遞過來的 value 參數為 null 會抛出 NullPointerException 異常。

private Optional(T value) {
        this.value = Objects.requireNonNull(value);
}      

Objects.requireNonNull() 源碼:

public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
}      

兩個構造方法都是 private 等級的通路權限,所有我們不能直接使用 new 關鍵字建立 Optional 執行個體。

of() 方法

of() 方法内部調用有參構造方法建立一個 Optional 執行個體。

因為 of() 方法在内部調用了有參構造方法,是以當 value 參數為 null 時,of() 方法會抛出 NullPointerException 異常,是以說 of() 方法會建立一個 value 屬性不為 null 的Optional 執行個體(建立成功的基礎上)。

public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
}      

測試:

User.java:

package entity;

public class User {

    // 使用者預設名字
    public static final String  DEFAULT_NAME = "Kaven";
    // 使用者預設年齡
    public static final int DEFAULT_AGE = 20;
    // 使用者的年齡
    private int age;
    // 使用者的名字
    private String name;

    public User(){}

    public User(int age , String name){
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        if(obj == null) return false;
        else{
            if(obj instanceof User){
                User user = (User) obj;
                if(this.name.equals((user).name) && this.age == user.age) return true;
                else return false;
            }
            else return false;
        }
    }
}      

testOptional.java:

package test;

import entity.User;

import java.util.Optional;

public class testOptional {

    public static void main(String[] args){

        Optional<User> optional = Optional.of(new User()); // 正常
        Optional<User> optional1 = Optional.of(null); // 抛出空指針異常
    }
}      

empty() 方法

EMPTY 屬性是一個 value 屬性為 null 的 Optional 執行個體,為什麼需要 EMPTY 屬性呢?以我的了解,EMPTY 屬性相當于代替了所有的 value 屬性為 null 的 Optional 執行個體,如果每次建立一個 value 屬性為 null 的 Optional 執行個體,都要調用 Optional 無參構造方法去申請記憶體建立一個 Optional 執行個體的話,還不如使用唯一一個 value 屬性為 null 的 Optional 執行個體來代替,這樣無論是在時間或者空間上來說都是劃得來的,是以 EMPTY 是有價值的。

private static final Optional<?> EMPTY = new Optional<>();      

empty() 方法就是傳回了 EMPTY 屬性,是以無論調用多少次 empty() 方法,傳回都是一樣的,傳回唯一一個 value 屬性為 null 的 Optional 執行個體-EMPTY 屬性。

public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
}      

測試:

Optional<User> optional = Optional.empty();
Optional<User> optional1 = Optional.empty();
System.out.println(optional == optional1);      

輸出:​

​true​

ofNullAble() 方法

看源碼應該很容易了解,就是當傳遞過來的 value 參數為 null 時,調用 empty(),value 參數不為 null 時,調用 of() 方法。

也就是說可以建立任何形式的 Optional 執行個體,無論 value 屬性是不是為 null,都可以建立成功。

public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
}      

測試:

Optional<User> optional = Optional.ofNullable(new User()); // 正常
Optional<User> optional1 = Optional.ofNullable(null); // 正常      

get() 方法

就是傳回 Optional 執行個體的 value 屬性。

public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
}      

測試:

Optional<User> optional = Optional.of(new User(20 ,"Kaven"));
User user = optional.get();
System.out.println(user.getAge());
System.out.println(user.getName());      

輸出:

20
Kaven      

isPresent() 方法

如果 Optional 執行個體的 value 屬性為 null ,傳回 false,否則傳回 true。

是以就是用來判斷 Optional 執行個體的 value 屬性是否為 null 的。

public boolean isPresent() {
        return value != null;
}      

ifPresent() 方法

參數是一個 Consumer 執行個體,在 ​​Consumer 接口 、 Predicate 接口初使用​​ 這篇部落格中我說過 ,我認為 Consumer 接口的主要作用是用來修改傳遞過來的參數的。是以我認為 ifPresent() 方法主要是用來修改 Optional 執行個體的 value 屬性的。

public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
}      

測試:

Optional<User> optional = Optional.of(new User(20 ,"Kaven"));
Consumer<User> consumer = user -> {
      user.setAge(21);
};
optional.ifPresent(consumer);
User user = optional.get();
System.out.println(user.getAge());
System.out.println(user.getName());      

輸出:

21
Kaven      

filter() 方法

從源碼中可以看出來,filter() 方法的參數是一個 Predicate 執行個體,是以以我的了解,可以先從方法的函數名開始,filter - 過濾,如 web 開發的過濾器,是不是有點熟悉的感覺,是以我覺得 filter() 方法也是起到過濾的作用,如果不比對 Predicate 執行個體的 test() 方法的 Optional 執行個體會傳回 EMPTY,也就是調用 empty(),否則傳回本身;當然如果這個 Optional 執行個體本身就是一個 EMPTY(value 為 null,或者說 isPresent() = false),也傳回本身。

public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
}      

測試:

Optional<User> optional = Optional.of(new User(20 ,"Kaven-1"));
Predicate<User> predicate1 = user -> {
    return user.getName().equalsIgnoreCase("Kaven");
};
Predicate<User> predicate2 = user -> {
    return user.getName().equalsIgnoreCase("Kaven-1");
};
Optional<User> optional1 = optional.filter(predicate1);
System.out.println(optional1);
Optional<User> optional2 = optional.filter(predicate2);
System.out.println(optional2.get().getName());      

輸出:

Optional.empty // 重寫了 toString()
Kaven-1      

map() 方法

map() 方法,方法名讓我想起了 mybatis 的映射檔案 Mapper.xml,其實這個方法的作用我覺得也是映射,把 ​

​Optional<T>​

​​ 執行個體映射成 ​

​Optional<U>​

​ 執行個體。

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));
        }
}      

測試:

Admin.java:

package entity;

public class Admin extends User{

    // 管理者數量
    private static int Admin_Number = 0;
    // 管理者 id,為了簡單管理者 id  就為目前管理者數量值
    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public static int adminNumAdd(){
        return ++Admin_Number;
    }
}      

我們通過 map() 方法,把 ​

​Optional<User>​

​​ 執行個體映射成 ​

​Optional<Admin>​

​。

Function<User , Admin> function = user ->{
      Admin admin = new Admin();
      admin.setAge(user.getAge());
      admin.setName(user.getName());
      admin.setId(Admin.adminNumAdd());
      return admin;
};

User user = new User(20 , "Kaven");
Optional<User> optional = Optional.of(user);
Optional<Admin> optionalAdmin = optional.map(function);
Admin admin = optionalAdmin.get();
System.out.println(admin.getAge());
System.out.println(admin.getName());
System.out.println(admin.getId());      

輸出:

20
Kaven
1      

flatMap() 方法

和 map() 方法沒有什麼差别,都是把 ​

​Optional<T>​

​​ 執行個體映射成 ​

​Optional<U>​

​​ 執行個體,隻不過 flatMap() 方法是通過 Function 執行個體更加直接的映射成 ​

​Optional<U>​

​​ ,而 map() 方法是先映射成 U 執行個體再調用 ofNullable() 方法建立 ​

​Optional<U>​

​ 執行個體,單詞 flat 也有直接的意思。

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));
        }
}      

測試:

代碼差不多

Function<User , Optional<Admin>> function = user ->{
     Admin admin = new Admin();
     admin.setAge(user.getAge());
     admin.setName(user.getName());
     admin.setId(Admin.adminNumAdd());
     Optional<Admin> optionalAdmin = Optional.of(admin);
     return optionalAdmin;
};

User user = new User(20 , "Kaven");
Optional<User> optional = Optional.of(user);
Optional<Admin> optionalAdmin = optional.flatMap(function);
Admin admin = optionalAdmin.get();
System.out.println(admin.getAge());
System.out.println(admin.getName());
System.out.println(admin.getId());      

輸出:

20
Kaven
1      

orElse()

看源代碼可以看出來,如果 Optional 執行個體的 value 屬性為 null,就傳回 other 參數,否則就傳回該 Optional 執行個體的 value 屬性。

在我看來,就是選擇值的優先級問題,總是會優先選擇目前這個 Optional 執行個體的 value 屬性,隻有當這個 Optional 執行個體的 value 屬性為 null 時,才選擇其他的值。

public T orElse(T other) {
        return value != null ? value : other;
}      

測試:

User user = new User(20 , "Kaven");
Optional<User> optional = Optional.ofNullable(null);
User user_test = optional.orElse(user);
System.out.println(user_test.getAge());
System.out.println(user_test.getName());

Optional<User> optional_test = Optional.ofNullable(new User(21 ,"Wang"));
user_test = optional_test.orElse(user);
System.out.println(user_test.getAge());
System.out.println(user_test.getName());      

輸出:

20
Kaven
21
Wang      

orElseGet() 、orElseThrow()

orElseGet() 源碼:

public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
}      

orElseThrow() 源碼:

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
}      

看源碼應該也很容易了解,和 orElse() 相對比了解就好了,我就不測試了。

equals()、hashCode()、toString()