回顾上午的问题
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
语句。
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); // 手动抛出异常
复制代码
使用 Optional 带来的变化
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 时候,我们经常会写的样式。会出现的问题:
- 如果某个值为 null,立马会报出 NPE
我们的解决方式
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 的原因就在这里。
Optional 的创建
empty
创建一个空的 Optional
对象
Optional<Object> empty = Optional.empty();
复制代码
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;
}
复制代码
of
Optional<B> optionalB = Optional.of(new B());
复制代码
of 方法中的参数如果为 null,会发生 NPE
Optional<Object> optional = Optional.of(null);
复制代码
of() 方法的实现
// 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
ofNullable 允许传入的参数为 null
A a = null;
Optional<A> optonal = Optional.ofNullable(a);
复制代码
ofNullable 的实现
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
复制代码
#Optinal 中获取值
get
A a = optionalA.get();
复制代码
如果 Optional
容器中不存在值,会抛出异常 NoSuchElementException("No value present")
get 的实现
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
复制代码
orElse
A a = optionalA.orElse(new A());
复制代码
如果 Optional
容器中不存在值,使用 orElse
方法中定义的值。
orElse 的实现
public T orElse(T other) {
return value != null ? value : other;
}
复制代码
orElseGet
A a = optionalA.orElseGet(A::new);
复制代码
如果 Optional
容器中不存在值,会执行定义的函数。
orElseGet 的实现
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
复制代码
orElseThrow
A a = optionalA.orElseThrow(RuntimeException::new);
复制代码
如果 Optional
容器中不存在值,会抛出指定的异常。与 get
方法的区别是,get
方法抛出的异常为固定的,该方法可以抛出指定的异常。
orElseThrow 的实现
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
复制代码
当 Optional
容器中的值为空时,使用了 throw
关键字。
map 和 flatMap
map
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"));
复制代码
flatMap
如果 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 不会进行拆包
Optional 提供的其他方法
isPresent
isPresent 用于判断 Optional
容器中值是否为空(null),不为空返回会 true,空返回 false
public boolean isPresent() {
return value != null;
}
复制代码
ifPresent
ifPresent 提供了执行函数式代码的能力,当 Optional
容器中的值不为空时,会执行传入的函数式代码。
optionalA.ifPresent(c -> System.out.println(c.getB()));
复制代码
ifPresent 的实现
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
复制代码
filter
通过执行传入的谓词
进行过滤,如果传入的 谓词
执行结果为 true
返回 Optional
容器本身,否则返回空容器。
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
复制代码