With Java, to safely access a deep nested reference like
a.b.c.d.e
, we'd usually have to specify null checks at each level or wrap in Optional
s and use orElse()
. (Unlike with languages like Kotlin/C# where a?.b?.c?.d?.e
or similar works.
I was wondering if the following helper method could be a reasonable alternative:
public <T> T valueOrNull(Supplier<T> expression) {
try {
return expression.get();
} catch (NullPointerException e) {
return null;
}
}
This can then be used safely with value = valueOrNull(() -> a.b.c.d.e)
.
Note: I understand that catching NullPointerException
s is usually frowned upon because of performance reasons and more, but was wondering if the usage here would be a reasonable exception.
You could write a function that takes a value and a getter to transform it, like so
public static <T1, T2> T1 coalesce(T2 value, Function<T2,T1> f1){
return f1.apply(value);
}
which you would then call like so coalesce(value, Clazz::getA)
.
For every step further in your chain, you need an additional Function in your coalesce function, like so
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);
}
for a depth of two, and
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);
}
for a depth of three and so on for further depths.
Example code:
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 is a class with a member of class B, B is a class with a member of class C, C is a class with a member of class String, with appropriate getters. Output is as expected:
null
null
null
1234
B@776ec8df
C@41629346
Nulls for the first three cases, where the string in C is null, the fourth has the value of the string, and fifth and sixth return objects of type B and C respectivelly.
I don't see a way to make the code much shorter unfortunately.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With