JAVA之工具類Optional

本文參考自: 原文地址

JAVA之工具類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));
    }
}

測試成功,只打印出了非空的結果.注意,此處如果用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的接口,所以不能被序列化,即不能作爲類的屬性或者方法入參.
發佈了39 篇原創文章 · 獲贊 2 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章