1. 程式人生 > 其它 >Java8 Optional使用總結

Java8 Optional使用總結

Java8 Optional 總結

模型類樣例

@Data
private static class User {
  private String name;
  private String age;
}

用例1

@Test(expected = NoSuchElementException.class)
public void whenCreateEmptyOptional_thenNull() {
  Optional<User> userOpt = Optional.empty();
  userOpt.get();
}

獲取一個包含null的Optional物件

Optional<User> userOpt = Optional.empty()

optional 的get方法

// 這裡會丟擲NoSuchElementException(extends RuntimeException)
// 因為 userOpt 是一個包含null的Optional物件,因為是非受檢異常
// 最好在get之前 先檢查一下比如 呼叫 userOpt.ifPresent()
userOpt.get();

用例2

@Test(expected = NullPointerException.class)
public void test2() {
  User user = null;
  Optional<User> userOptional = Optional.of(user);
}

Optional 的靜態方法of 不能傳入null物件,否則報空指標異常

看原始碼

/**
 * Optional 原始碼
 */
public static <T> Optional<T> of(T value) {
  return new Optional<>(value);
}

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

// Objects 原始碼
public static <T> T requireNonNull(T obj) {
  if (obj == null)
    throw new NullPointerException();
  return obj;
}

用例3

@Test
public void test_ofNullable() {
  User user = null;
  Optional<User> userOptional = Optional.ofNullable(user);
}

Optional 靜態方法ofNullable可以傳入null,傳入null會得到一個包含null的optional物件

原始碼

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

用例4

    @Test
    public void test_getOptionalValue() {
        String name = "jim";
        Optional<String> nameOptional = Optional.of(name);
        if (nameOptional.isPresent()) {
            System.out.println(nameOptional.get());
        }
    }

Optional 例項方法 isPresent,判斷optional 的value是不是null

原始碼

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

用例5

    @Test
    public void test_ifPresentFunc() {
        String name = "jim";
        Optional<String> nameOptional = Optional.of(name);
        nameOptional.ifPresent(value -> System.out.println("ifPresent=>" + value));
    }

ifPresent(Consumer consumer) :如果有值就執行一個consumer這個函式

原始碼

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

用例6

@Test
public void test_filter() {
  String str = "abcd";
  Optional<String> stringOptional = Optional.of(str);
  stringOptional.filter(value -> value.contains("e"))
    						.ifPresent(value -> System.out.println("過濾後: " + value));
}

filter用於條件過濾,如果滿足傳入的Predicate函式,則返回this,不滿足返回一個包含null的Optional物件(既後續操作不做了,比如上面的ifPresent)

原始碼

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

用例7 map 用法

@Test
public void test_map() {
 String str = "abcd";
 Optional<String> stringOptional = Optional.of(str);
 stringOptional.map(String::toUpperCase)
   						.ifPresent(value -> System.out.println("對映後: " + value));
}

map用於對映,將物件轉化成另一個物件,或者是對內容做變形(比如上面的將字串轉換為大寫),並返回一個Optional物件;如果呼叫map的Optional物件為空值Optional物件==,也會返回一個包含空值的Optional物件

用例8 flatMap用法

flatMap 和 map 的區別就是map自動幫你封裝成了Optional物件,而flatMap需要你自己手動封裝成Optional物件(這樣看來map更好用)

@Test
public void test_flatMap() {
  String str = "abcd";
  Optional<String> stringOptional = Optional.of(str);
  stringOptional.flatMap(value -> Optional.ofNullable(value.toUpperCase()))
    .ifPresent(value -> System.out.println("flatMap對映後: " + value));
}

用例9 orElse用法

    @Test
    public void test_orElse() {
        String str = null;
        Optional<String> stringOptional = Optional.ofNullable(str);
        System.out.println(stringOptional.orElse("qwerty"));
    }

orElse即當呼叫它的物件是value是null的Optional物件時就執行返回引數的物件引用的函式

相對於orElseGet缺點是:

執行到orElse時,括號內的語句一定會先執行,可能會造成一定的浪費(比如是個大物件)

如果需要orElse中臨時建立物件,建議使用orElseGet,如果是已經建立好的物件的引用就無所謂了

原始碼(可以看到other進來的時候已經建立完畢,即使是個null的Optional物件)

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

用例10 orElseGet用法

@Test
public void test_orElseGet() {
  String str = null;
  Optional<String> stringOptional = Optional.ofNullable(str);
  System.out.println(stringOptional.orElseGet(() -> "qwerty"));
}

原始碼

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

從原始碼可以看出來 只有value為null時,才會執行傳入進來的函式,

這樣當value不為null時,就可以避擴音前建立處物件所帶來的浪費了

用例11 orElseThrow

@Test
public void test_orElseThrow() {
  String str = null;
  Optional<String> stringOptional = Optional.ofNullable(str);
  System.out.println(stringOptional.orElseThrow(RuntimeException::new));
}

orElseThrow 如果是null的Optional物件呼叫它,會丟擲括號內的異常(這個異常類必須要有無參建構函式

原始碼

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