Java 8中所謂的Optional對象,即一個容器對象,該對象可以包含一個null或非null值。如果該值不為null,則調用isPresent()方法將返回true,且調用get()方法會返回該值。
另外,該對象還有其它方法:
如可以使用orElse()方法給Optional對象設定默認值(當值為null時,會使用默認值);
使用ifPresent()方法來執行一段代碼(當值不為null時,執行代碼段)。
Optional主要被用於Java 8的Stream中,簡單舉個例子:
package optional; import java.util.Optional; import java.util.stream.Stream; public class Snippet { public static void main(String[] args) { Stream<String> names = Stream.of("Lamurudu", "Okanbi", "Oduduwa"); Optional<String> startswl = names.filter(name -> name.startsWith("L")).findFirst(); //判斷是否不為null if(startswl.isPresent()){ System.out.println(startswl.get()); } //if值為null:打印“null”;if值不為null:打印原值 System.out.println(startswl.orElse("null")); //if值不為null,執行Lambda表達式 startswl.ifPresent(name -> { String s = name.toUpperCase(); System.out.println(s); }); } }
減少NullPointerException異常
寫出更加優雅的代碼
Optional類的屬性和方法如下:
我們一個個看,先看兩個成員屬性;
成員屬性
如下,一個是EMPTY常量,即存放空值的Optional對象,另一個是value,即被存放的值,可為null或非null值;
/** * Common instance for {@code empty()}. */ private static final Optional<?> EMPTY = new Optional<>(); /** * If non-null, the value; if null, indicates no value is present */ private final T value;
構造方法
兩個構造方法,注意都是私有的
1、創建一個包含空值的Optional對象;
2、創建一個非空值的Optional對象;
private Optional() { this.value = null; }
private Optional(T value) { this.value = Objects.requireNonNull(value); }
這個方法很簡單,作用是返回一個Optional實例,裡面存放的value是null,源碼如下:
public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }
of(T value)方法
很簡單,就是返回一個包含非空值的Optional對象
public static <T> Optional<T> of(T value) { return new Optional<>(value); }
ofNullable(T value)方法
很簡單,返回一個可以包含空值的Optional對象
public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); }
get()方法
得到Optional對象裡的值,如果值為null,則拋出NoSuchElementException異常
public T get() { if (value == null) { throw new NoSuchElementException("No value present"); } return value; }
isPresent()方法
很簡單,判斷值是否不為null
public boolean isPresent() { return value != null; }
ifPresent(Consumer<? super T> consumer)方法
當值不為null時,執行consumer
public void ifPresent(Consumer<? super T> consumer) { if (value != null) consumer.accept(value); }
舉個例子,ifPresent方法執行Lambda表達式,將值轉換為大寫並打印:
package optional; import java.util.Optional; public class Snippet { public static void main(String[] args) { Optional<String> test = Optional.ofNullable("abcDef"); //值不為null,執行Lambda表達式, test.ifPresent(name -> { String s = name.toUpperCase(); System.out.println(s); }); //打印ABCDEF } }
filter(Predicate<? super T> predicate)方法
看方法名就知道,該方法是過濾方法,過濾符合條件的Optional對象,這裡的條件用Lambda表達式來定義,
如果入參predicate對象為null將拋NullPointerException異常,
如果Optional對象的值為null,將直接返回該Optional對象,
如果Optional對象的值符合限定條件(Lambda表達式來定義),返回該值,否則返回空的Optional對象
源碼如下:
public Optional<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); }
使用示例:
package optional; import java.util.Optional; public class Snippet { public static void main(String[] args) { Optional<String> test = Optional.ofNullable("abcD"); //過濾值的長度小於3的Optional對象 Optional<String> less3 = test.filter((value) -> value.length() < 3); //打印結果 System.out.println(less3.orElse("不符合條件,不打印值!")); } }
map(Function<? super T, ? extends U> mapper)方法
前面的filter方法主要用於過濾,一般不會修改Optional裡面的值,map方法則一般用於修改該值,並返回修改後的Optional對象
如果入參mapper對象為null將拋NullPointerException異常,
如果Optional對象的值為null,將直接返回該Optional對象,
最後,執行傳入的lambda表達式,並返回經lambda表達式操作後的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)); } }
使用示例:
package optional; import java.util.Optional; public class Snippet { public static void main(String[] args) { Optional<String> test = Optional.ofNullable("abcD"); //將值修改為大寫 Optional<String> less3 = test.map((value) -> value.toUpperCase()); //打印結果 ABCD System.out.println(less3.orElse("值為null,不打印!")); } }
flatMap(Function<? super T, Optional<U>> mapper)方法
flatMap方法與map方法基本一致,唯一的區別是,
如果使用flatMap方法,需要自己在Lambda表達式裡將返回值轉換成Optional對象,
而使用map方法則不需要這個步驟,因為map方法的源碼裡已經調用了Optional.ofNullable方法;
源碼:
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)); } }
使用示例:
package optional; import java.util.Optional; public class Snippet { public static void main(String[] args) { Optional<String> test = Optional.ofNullable("abcD"); //使用flatMap,將值修改為大寫 Optional<String> less3 = test.flatMap((value) -> Optional.ofNullable(value.toUpperCase())); //使用map,將值修改為大寫 //Optional<String> less3 = test.map((value) -> value.toUpperCase()); //打印結果 ABCD System.out.println(less3.orElse("值為null,不打印!")); } }
orElse(T other)方法
很簡單,當值為null時返回傳入的值,否則返回原值;
源碼:
public T orElse(T other) { return value != null ? value : other; }
orElseGet(Supplier<? extends T> other)方法
功能與orElse(T other)類似,不過該方法可選值的獲取不是通過參數直接獲取,而是通過調用傳入的Lambda表達式獲取
源碼:
public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); }
使用示例:
package optional; import java.util.Optional; public class Snippet { public static void main(String[] args) { Optional<String> test = Optional.ofNullable(null); System.out.println(test.orElseGet(() -> "hello")); //將打印hello } }
orElseThrow(Supplier<? extends X> exceptionSupplier)方法
當遇到值為null時,根據傳入的Lambda表達式跑出指定異常
源碼
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throw exceptionSupplier.get(); } }
使用示例:
package optional; import java.util.Optional; public class Snippet { public static void main(String[] args) { Optional<String> test = Optional.ofNullable(null); //這裡的Lambda表達式為構造方法引用 System.out.println(test.orElseThrow(NullPointerException::new)); //將打印hello } }
jdk1.8.0_31源碼
https://blog.idrsolutions.com/2015/04/java-8-optional-class-explained-in-5-minutes/
https://www.voxxed.com/blog/2015/05/why-even-use-java-8-optional/
http://unmi.cc/proper-ways-of-using-java8-optional/