public class A {
private B b;
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
public class B {
private String bName;
private String bAge;
public String getbName() {
return bName;
}
public void setbName(String bName) {
this.bName = bName;
}
public String getbAge() {
return bAge;
}
public void setbAge(String bAge) {
this.bAge = bAge;
}
}
複製代碼
已經存在兩個類,而且互相嵌套,並且不容許修改, A 、B 兩個類的結構,咱們要安全的訪問 A B中的值,儘量少的使用 if
語句。java
A a = null;
Optional<A> a1 = Optional.ofNullable(a);
Optional<B> b = a1.filter((t) -> t.getB() != null).map(A::getB);
// 上面一行代碼的問題是, t 有可能會爲 null ,從而引起 NPE
B b2 = b.get();
複製代碼
Optional<A> a1 = Optional.ofNullable(a);
Optional<B> b = a1.map(A::getB);
b.get(); // 有可能會拋異常,由於若是 b 爲 null,那麼獲得的 Optional 爲 empty 建立的
b.orElse(new B()); // 沒有問題,返回 new B 的對象
b.orElseGet(() -> B :: new); // 沒有問題,返回 new B 的對象
b.orElseThrow(() -> YdException::new); // 手動拋出異常
複製代碼
public class PersonNoOptional {
private Car car;
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public static class Car{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
複製代碼
上面的代碼是沒有使用 Optional 時候,咱們常常會寫的樣式。會出現的問題:設計模式
咱們的解決方式安全
public class OptionService {
public void opt() {
PersonNoOptional p = new PersonNoOptional();
PersonNoOptional.Car car = p.getCar();
if (car != null) {
// ....
}
}
}
複製代碼
會添加不少的 if
來進行判斷,甚至還有空對象設計模式(Null Object Pattern) 來處理這一類的問題。Java 8 爲咱們帶來了 Optional
添加新的解決方式。函數
public class PersonOptional {
private Optional<PersonNoOptional.Car> car;
public Optional<PersonNoOptional.Car> getCar() {
return car;
}
public void setCar(PersonNoOptional.Car car) {
this.car = Optional.of(car);
}
public static class Car {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
複製代碼
Peron 有可能會沒有 Car,可是每一輛 Car 都必須有 name,因此咱們對 Car 使用了 Optional 包裝,而 name 沒有使用 Optional 的緣由就在這裏。ui
建立一個空的 Optional
對象this
Optional<Object> empty = Optional.empty();
複製代碼
private static final Optional<?> EMPTY = new Optional<>();
private Optional() { this.value = null; }
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
複製代碼
Optional<B> optionalB = Optional.of(new B());
複製代碼
of 方法中的參數若是爲 null,會發生 NPEspa
Optional<Object> optional = Optional.of(null);
複製代碼
// Objects.requireNonNull 的實現
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
複製代碼
ofNullable 容許傳入的參數爲 null設計
A a = null;
Optional<A> optonal = Optional.ofNullable(a);
複製代碼
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
複製代碼
#Optinal 中獲取值code
A a = optionalA.get();
複製代碼
若是 Optional
容器中不存在值,會拋出異常 NoSuchElementException("No value present")
對象
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
複製代碼
A a = optionalA.orElse(new A());
複製代碼
若是 Optional
容器中不存在值,使用 orElse
方法中定義的值。
public T orElse(T other) {
return value != null ? value : other;
}
複製代碼
A a = optionalA.orElseGet(A::new);
複製代碼
若是 Optional
容器中不存在值,會執行定義的函數。
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
複製代碼
A a = optionalA.orElseThrow(RuntimeException::new);
複製代碼
若是 Optional
容器中不存在值,會拋出指定的異常。與 get
方法的區別是,get
方法拋出的異常爲固定的,該方法能夠拋出指定的異常。
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
複製代碼
當 Optional
容器中的值爲空時,使用了 throw
關鍵字。
public class A {
private B b;
public B getB() {
return b;
}
}
public class B {
private Name bName;
private String bAge;
public Name getbName() {
return bName;
}
public void setbName(Name bName) {
this.bName = bName;
}
public String getbAge() {
return bAge;
}
public void setbAge(String bAge) {
this.bAge = bAge;
}
public static class Name{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
複製代碼
A B 兩個類的結構關係是互相嵌套,咱們要取出 b.Name.getName() 的值
Optional<String> aName = optionalA.map(A::getB)
.map(B::getbName)
.map(B.Name::getName);
System.out.println(aName.orElse("kkk"));
複製代碼
若是 B 在 A 的嵌套中,使用了 Optional 包裝
public class A {
private Optional<B> b;
public Optional<B> getB() {
return b;
}
}
複製代碼
再使用上面的訪問,就會編譯報錯。
緣由:
Optional<Optional<B>> optional = optionalA.map(A::getB);
複製代碼
map 的返回外面被包裝了一層 Optional
,想要達到上面的效果,須要拆掉一層 Optional
的包裝,那麼此時就可使用 flatMap
來打散一層 Optional
的包裝
String kkk = optionalA.flatMap(A::getB)
.map(B::getbName)
.map(B.Name::getName)
.orElse("kkk");
複製代碼
ypxh就能夠順利訪問了
map 和 flatMap 的區別在於,flatMap 會進行拆包(將外面的層包裝拆除)的動做,而 map 不會進行拆包
isPresent 用於判斷 Optional
容器中值是否爲空(null),不爲空返回會 true,空返回 false
public boolean isPresent() {
return value != null;
}
複製代碼
ifPresent 提供了執行函數式代碼的能力,當 Optional
容器中的值不爲空時,會執行傳入的函數式代碼。
optionalA.ifPresent(c -> System.out.println(c.getB()));
複製代碼
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
複製代碼
經過執行傳入的謂詞
進行過濾,若是傳入的 謂詞
執行結果爲 true
返回 Optional
容器自己,不然返回空容器。
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
複製代碼