我们说我有下一段代码:
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而不是A
,B
,C
,D
我可以Optional<A>
,Optional<B>
等等。
编写更美观的代码以阻止所有这些空检查的正确方法是什么? 另外,一旦变量(a,b,c,d ..)之一为空,有没有办法做我所要求的添加抛出异常?
答案 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);