使用Java,可以安全地访问深层嵌套引用
a.b.c.d.e
,我们通常必须在每个级别指定空检查或包装Optional
并使用orElse()
。 (与Kotlin / C#等语言不同,其中a?.b?.c?.d?.e
或类似作品。
我想知道以下帮助方法是否是一个合理的选择:
public <T> T valueOrNull(Supplier<T> expression) {
try {
return expression.get();
} catch (NullPointerException e) {
return null;
}
}
然后可以安全地使用value = valueOrNull(() -> a.b.c.d.e)
。
注意:我理解,由于性能原因等原因,捕捉NullPointerException
通常不赞成,但是想知道这里的用法是否是一个合理的例外。
答案 0 :(得分:1)
你可以写一个带值的函数和一个getter来转换它,就像这样
public static <T1, T2> T1 coalesce(T2 value, Function<T2,T1> f1){
return f1.apply(value);
}
然后你会像coalesce(value, Clazz::getA)
那样打电话。
对于链中的每一步,您需要在合并函数中使用附加函数,如此
public static <T1, T2, T3> T1 coalesce(T3 value, Function<T3,T2> f1, Function<T2,T1> f2){
T2 t2 = f1.apply(value);
if(t2 == null)
return null;
return f2.apply(t2);
}
深度为2,
public static <T1, T2, T3, T4> T1 coalesce(T4 value, Function<T4,T3> f1, Function<T3,T2> f2, Function<T2,T1> f3){
T3 t3 = f1.apply(value);
if(t3 == null)
return null;
T2 t2 = f2.apply(t3);
if(t2 == null)
return null;
return f3.apply(t2);
}
深度为3,等等进一步深度。
示例代码:
A test1 = new A(null);
A test2 = new A(new B(null));
A test3 = new A(new B(new C(null)));
A test4 = new A(new B(new C("1234")));
System.out.println(coalesce(test1, A::getB, B::getC, C::getS));
System.out.println(coalesce(test2, A::getB, B::getC, C::getS));
System.out.println(coalesce(test3, A::getB, B::getC, C::getS));
System.out.println(coalesce(test4, A::getB, B::getC, C::getS));
System.out.println(coalesce(test2, A::getB));
System.out.println(coalesce(test3, A::getB, B::getC));
A是具有类B成员的类,B是具有类C成员的类,C是具有类String成员的类,具有适当的getter。输出符合预期:
null
null
null
1234
B@776ec8df
C@41629346
前三种情况为空,其中C中的字符串为null,第四种具有字符串的值,第五种和第六种返回的对象分别为B和C类型。
遗憾的是,我没有办法让代码更短。