jdk8新特性Optional
阿新 • • 發佈:2018-12-07
前言
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";
}
}