问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 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
语句。
1 2 3 4 5 A a = null ; Optional<A> a1 = Optional.ofNullable(a); Optional<B> b = a1.filter((t) -> t.getB() != null ).map(A::getB); B b2 = b.get();
1 2 3 4 5 6 Optional<A> a1 = Optional.ofNullable(a); Optional<B> b = a1.map(A::getB); b.get(); b.orElse(new B()); b.orElseGet(() -> B :: new ); b.orElseThrow(() -> YdException::new );
使用 Optional 带来的变化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 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 时候,我们经常会写的样式。会出现的问题:
我们的解决方式
1 2 3 4 5 6 7 8 9 10 11 12 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
添加新的解决方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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
对象
1 Optional<Object> empty = Optional.empty();
empty() 方法的实现 1 2 3 4 5 6 7 8 9 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 1 Optional<B> optionalB = Optional.of(new B());
of 方法中的参数如果为 null,会发生 NPE
1 Optional<Object> optional = Optional.of(null );
of() 方法的实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 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
1 2 A a = null ; Optional<A> optonal = Optional.ofNullable(a);
ofNullable 的实现 1 2 3 public static <T> Optional<T> ofNullable (T value) { return value == null ? empty() : of(value); }
#Optinal 中获取值
get
如果 Optional
容器中不存在值,会抛出异常 NoSuchElementException("No value present")
get 的实现 1 2 3 4 5 6 public T get () { if (value == null ) { throw new NoSuchElementException("No value present" ); } return value; }
orElse 1 A a = optionalA.orElse(new A());
如果 Optional
容器中不存在值,使用 orElse
方法中定义的值。
orElse 的实现 1 2 3 public T orElse (T other) { return value != null ? value : other; }
orElseGet 1 A a = optionalA.orElseGet(A::new );
如果 Optional
容器中不存在值,会执行定义的函数。
orElseGet 的实现 1 2 3 public T orElseGet (Supplier<? extends T> other) { return value != null ? value : other.get(); }
orElseThrow 1 A a = optionalA.orElseThrow(RuntimeException::new );
如果 Optional
容器中不存在值,会抛出指定的异常。与 get
方法的区别是,get
方法抛出的异常为固定的,该方法可以抛出指定的异常。
orElseThrow 的实现 1 2 3 4 5 6 7 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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 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() 的值
1 2 3 4 Optional<String> aName = optionalA.map(A::getB) .map(B::getbName) .map(B.Name::getName); System.out.println(aName.orElse("kkk" ));
flatMap 如果 B 在 A 的嵌套中,使用了 Optional 包装
1 2 3 4 5 6 7 8 public class A { private Optional<B> b; public Optional<B> getB () { return b; } }
再使用上面的访问,就会编译报错。
原因:
1 Optional<Optional<B>> optional = optionalA.map(A::getB);
map 的返回外面被包装了一层 Optional
,想要达到上面的效果,需要拆掉一层 Optional
的包装,那么此时就可以使用 flatMap
来打散一层 Optional
的包装
1 2 3 4 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
1 2 3 public boolean isPresent () { return value != null ; }
ifPresent ifPresent 提供了执行函数式代码的能力,当 Optional
容器中的值不为空时,会执行传入的函数式代码。
1 optionalA.ifPresent(c -> System.out.println(c.getB()));
ifPresent 的实现 1 2 3 4 public void ifPresent (Consumer<? super T> consumer) { if (value != null ) consumer.accept(value); }
filter 通过执行传入的谓词
进行过滤,如果传入的 谓词
执行结果为 true
返回 Optional
容器本身,否则返回空容器。
1 2 3 4 5 6 7 public Optional<T> filter (Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this ; else return predicate.test(value) ? this : empty(); }