避免使用Optionals分支null检查

时间:2017-02-06 11:26:01

标签: java java-8 optional

我们说我有下一段代码:

void doSmtng(A a){
    if (a!=null){
        B b = a.getB();
        if (b != null){
            C c = b.getC();
            if (c != null){
                d = c.getD();
            }
        }
    }
    doSmtngWithD(d);
}

让我们说我可以更改API而不是ABCD我可以Optional<A>Optional<B>等等。

编写更美观的代码以阻止所有这些空检查的正确方法是什么? 另外,一旦变量(a,b,c,d ..)之一为空,有没有办法做我所要求的添加抛出异常?

2 个答案:

答案 0 :(得分:6)

另一种Optional方式,Holger在评论中也提到了这一点:

D d = Optional.ofNullable(a)
              .map(A::getB)
              .map(B::getC)
              .map(C::getD)
              .orElseThrow(/* your exception */);

这可以按原样应用于您的代码。您无需重写访问器方法。只要返回第一个null值,就会抛出异常。但是当抛出异常时,你不知道究竟是哪一个null

如果您真的想知道这一点,那么您可能更擅长实施一种简单的方法,即null - 只检查而不是使用Optional,例如。

static <T> T mapIfNotNull(T value) {
  if (value == null) {
    // throw your exception...
  }
  return value;
}

并在没有您的条件的情况下使用它,如下所示:

A a = ...
B b = mapIfNotNull(a.getB());
C c = mapIfNotNull(b.getC());
D d = mapIfNotNull(c.getD());

通过这种方式,您可以在每个步骤中抛出所需的异常...(如果您提供了另外一个参数,您可以在其中提供自定义异常,例如mapIfNotNull(T value, Supplier<RuntimeException> exceptionSupplier))。 或者只需在评论中使用Objects.requireNonNull作为Holger状态,如果NullPointerException满足您的需求。

如果您还想检查,您调用getXX的对象是否为空,则可能需要使用以下方法:

static <S, T> T map(S source, Function<S, T> mapFunction) {
  if (source == null) { // or again: Objects.requireNonNull(source,..)
    // throw exception due to source
  }
  T value = mapFunction.apply(source);
  if (value == null) { // or Objects.requireNonNull(value,..)
    // throw exception due to missing value
  }
  return value;
}
呼叫工作几乎相同:

A a = ...
B b = map(a, A::getB);
C c = map(b, B::getC);
D d = map(c, C::getD);

答案 1 :(得分:5)

Optional<A> a开始:

a.flatMap(A::getOptionalB)
   .flatMap(B::getOptionalC)
   .flatMap(C::getOptionalD)
   .ifPresent(d -> doSomethingWithD(d));

如果您想丢失其中一个异常,则抛出异常:

D d = a.flatMap(A::getOptionalB)
       .flatMap(B::getOptionalC)
       .flatMap(C::getOptionalD)
       .orElseThrow(() -> new SomeKindOfException());
doSomethingWithD(d);