Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternative for Null Coalescing Operator

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 Optionals 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 NullPointerExceptions is usually frowned upon because of performance reasons and more, but was wondering if the usage here would be a reasonable exception.

like image 459
Naufal Avatar asked May 17 '17 08:05

Naufal


1 Answers

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.

like image 192
Jure Kolenko Avatar answered Sep 21 '22 15:09

Jure Kolenko