1. 程式人生 > >jdk8新特性Optional

jdk8新特性Optional

前言

Java世界中最為常見的異常就是npe了,所以使用物件前對物件判空是保證程式碼魯棒性的重要保證,因此在jdk7之前我們經常寫出這樣的程式碼:

        if (someObject != null) {
            if (someObject.someField != null) {
                if (someObject.someField.someField != null) {
                    Systemout.println(someObject.someField.someField)
                }
            }
        }

程式碼邏輯雖然不復雜但是過於繁複,於是在jdk8提供了一個新的特性Optional,結合lambda表示式可以極大地簡化我們的判空操作,先來看看使用Optional如何重構上面那一段程式碼

Optional.ofNullable(someObject).map(SomeObject::getSomeField).map(SomeField::getSomeField).ifPresent(System.out::println);

可以看到藉助於lambda表示式,之前的多重巢狀的判空操作只需要一行程式碼就可以完成。

再來看看通過Optional規避集合越界的程式碼

List list = new ArrayList();

Optional.ofNullable(list).filter(e -> e.size() > 0).map(e -> e.get(1)).ifPresent(System.out::println);

這裡是有了Optional中的filter操作符,只有符合lambda表示式條件的元素才不會被過濾進入下一個操作符map,因此長度不符合要求的陣列根本不會被取值。

除了上述的map,filter和isPresent操作符,Optional還提供了一系列其他的常用操作符。

Optional操作符

1 ofNullable

傳入的物件可以為null

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

2 of

傳入的物件不可以為null,否則丟擲NullPointerException

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

例子

public static void main(String[] args) {

    User user = new User();
    User user1 = null;

    // 傳遞進去的物件不可以為null,如果為null則丟擲異常
    Optional<User> op1 = Optional.of(user1);

    // 傳遞進去的物件可以為null,如果為null則返回一個沒有裝載物件的Optional容器
    Optional<User> op2 = Optional.ofNullable(user);
}

3 ifPresent

首先來看看ifPresent(Consumer<? super T> consumer)方法

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

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

複製程式碼如果容器中的物件存在,則呼叫accept方法,比如說:

public static void main(String[] args) {

    User user = new User();
    user.setName("Java3y");
    test(user);
}

public static void test(User user) {

    Optional<User> optional = Optional.ofNullable(user);

    // 如果存在user,則列印user的name
    optional.ifPresent((value) -> System.out.println(value.getName()));

    // 舊寫法
    if (user != null) {
        System.out.println(user.getName());
    }
}

4 orElseGet和orElseThrow

直接看原始碼:

// 如果物件存在,則直接返回,否則返回由Supplier介面的實現用來生成預設值
public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
}


@FunctionalInterface
public interface Supplier<T> {
    T get();
}


// 如果存在,則返回。否則丟擲supplier介面建立的異常
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}

例子:

public static void main(String[] args) {

    User user = new User();
    user.setName("Java3y");
    test(user);
}

public static void test(User user) {

    Optional<User> optional = Optional.ofNullable(user);

    // 如果存在user,則直接返回,否則創建出一個新的User物件
    User user1 = optional.orElseGet(() -> new User());
    
    // 舊寫法
    if (user != null) {
        user = new User();
    }
}

總的來說跟我們上面所講的orElse()差不多,只不過它可以通過Supplier介面的實現來生成預設值。

5 filter

// 如果容器中的物件存在,並且符合過濾條件,返回裝載物件的Optional容器,否則返回一個空的Optional容器
public Optional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    if (!isPresent())
        return this;
    else
        return predicate.test(value) ? this : empty();
}


// 介面
@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);
}

由於返回的是Optional物件,我們就可以實現鏈式呼叫了!
例子:

public static void test(User user) {

    Optional<User> optional = Optional.ofNullable(user);

    // 如果容器中的物件存在,並且符合過濾條件,返回裝載物件的Optional容器,否則返回一個空的Optional容器
    optional.filter((value) -> "Java3y".equals(value.getName()));
}

6 map

直接看原始碼:

// 如果容器的物件存在,則對其執行呼叫mapping函式得到返回值。然後建立包含mapping返回值的Optional,否則返回空Optional。
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));
    }
}


// 介面
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

例子:

public static void test(User user) {

    Optional<User> optional = Optional.ofNullable(user);

    // 如果容器的物件存在,則對其執行呼叫mapping函式得到返回值。然後建立包含mapping返回值的Optional,否則返回空Optional。
    optional.map(user1 -> user1.getName()).orElse("Unknown");
}

// 上面一句程式碼對應著最開始的老寫法:

public String tradition(User user) {
    if (user != null) {
        return user.getName();
    }else{
        return "Unknown";
    }
}