Nullcheck method using java8 method reference possible?

3.3k views Asked by At

Due to rich profiling, our Java code is cluttered with outputs of method results of nullable objects.

It looks like this

namedObject == null ? "?" : namedObject.getName()

is it possible to write a static method for this? (e.g. looking like this):

Util.nvl( namedObject, NamedObject::getName, "?" )

What would = Util.nvl look like? I've experimented a bit an searched google but yielded no result.

This does not work:

public static <T> T nvl(T value, Function<T, ?> method, T nullSubstition) {
    return value == null ? nullSubstition : (T) method.apply(value);
}

The compiler tells me: non-static method getName() cannot be referenced from a static context

2

There are 2 answers

1
JB Nizet On BEST ANSWER

Your signature can't be correct. You want your method to take the NamedObject as first argument (so T is a NamedObject), and to return a String (so now T is String).

You need two generic type parameters:

public class Utils {

    public static <O, T> T nvl(O value, Function<O, T> method, T nullSubstition) {
        return value == null ? nullSubstition : method.apply(value);
    }

    static class NamedObject {
        String getName() {
            return "foo";
        }
    }

    public static void main(String[] args) {
        NamedObject foo = null;
        String name = Utils.nvl(foo, NamedObject::getName, "bar");
        System.out.println("name = " + name); // name = bar

        foo = new NamedObject();
        name = Utils.nvl(foo, NamedObject::getName, "bar");
        System.out.println("name = " + name); // name = foo
    }
}

An even better signature, allowing more flexibility, would be

public static <O, T> T nvl(O value, Function<? super O, ? extends T> method, T nullSubstition) {
    return value == null ? nullSubstition : method.apply(value);
}
3
Mureinik On

Your method's generics aren't defined correctly. You're attempting to create a method that receives an object of a certain type (T, for argument's sake, or a NamedObject in the given example), and applies a method that returns an object of a different type (S, for argument's sake, or String in the given example), or a default S value if the passed object is null:

public static <T, S> S nvl(T value, Function<T, S> method, S nullSubstition) {
    return value == null ? nullSubstition : (S) method.apply(value);
}

Note that Java 8's Optional may allow you to write this in a more elegant way (although elegance is somewhat in the eye of the beholder):

public static <T, S> S nvl(T value, Function<T, S> method, S nullSubstition) {
    return Optional.ofNullable(value).map(method).orElse(nullSubstition);
}