prom85
prom85

Reputation: 17838

calling function should return default value, if object (or any function result) is null

Is it possible to wrap following code in a reusable function?

EDIT: this is just an example, I want a working solution for ALL recursion depths

what I want is that following code is generated:

if (MyObject o == null || 
    o.getSubObject() == null ||
    o..getSubObject().getSubSubObject() == null /*|| 
    ... */)
    return defaultValue;
return o.getSubObject().getSubObject()/*...*/.getDesiredValue();

by calling something like

Object defaultValue = null;
Object result = NullSafeCall(o.getSubObject().getSubObject()/*...*/.getDesiredValue(), defaultValue);

The seond code block is just an idea, I don't care how it looks like, all I want is that I, if desired, can avoid all the null checks before calling a deeper function...

Injection could do this propably, but is there no other/easier solution? Never looked at injection before yet...

EDIT2: example in another language: http://groovy.codehaus.org/Operators#Operators-SafeNavigationOperator

Upvotes: 1

Views: 2695

Answers (5)

Joachim Isaksson
Joachim Isaksson

Reputation: 180927

Java8 helps to get the closest you'll get to your syntax with decent performance I suspect;

// Evaluate with default 5 if anything returns null.
int result = Optional.eval(5, o, x->x.getSubObject(), x->x.getDesiredValue());

This can be done with this utility class;

class Optional {
    public static <T, Tdef, T1> Tdef eval(Tdef def, T input, Function<T,T1> fn1,
                                          Function<T1, Tdef> fn2)
    {
        if(input == null) return def;
        T1 res1 = fn1.apply(input);
        if(res1 == null) return def;
        return fn2.apply(res1);
    }
}

Sadly, you'll need a separate eval() defined per number of method calls in the chain, so you may want to define a few, but compile time type safe and reusable with just about any calls/types.

Upvotes: 1

c.s.
c.s.

Reputation: 4816

What you want is not possible. It is essential to understand that using this syntax: Object result = NullSafeCall(o.getSubObject().getSubObject() ...); the part of o.getSubObject().getSubObject() will be evaluated before any control passes to the function/method thus throwing the exception.

It is required to have some type of context before executing such code. The closest to this I could think of, can be done using anonymous inner classes like the example below:

// intended to be implemented by an anonymous inner class
interface NullSafeOperation<T> {
    public T executeSafely();
};

// our executor that executes operations safely
public static class NullSafeExecutor<T> {
    public NullSafeExecutor() {}

    public T execute(T defaultValue, NullSafeOperation<T> nso) {
        T result = defaultValue;
        try {
            result = nso.executeSafely();
        } catch(NullPointerException e) {
            // ignore
        }
        return result;
    }

    // utility method to create a new instance and execute in one step
    public static <T> T executeOperation(T defaultValue, NullSafeOperation<T> nso) {
        NullSafeExecutor<T> e = new NullSafeExecutor<T>();
        T result = e.execute(defaultValue, nso);
        return result;
    }
}


public static void main(String[] args) {

    final String aNullString = null;

    String result = NullSafeExecutor.executeOperation("MyDefault", new NullSafeOperation<String>() {
        @Override
        public String executeSafely() {
            // trying to call a method on a null string
            // it will throw NullPointerException but it will be catched by the executor
            return aNullString.trim(); 
        }
    });

    System.out.println("Output = " + result); // prints: Output = MyDefault
}

Upvotes: 0

Malav
Malav

Reputation: 203

i would suggest just replace

Object result = NullSafeCall(o.getSubObject().getDesiredValue(), defaultValue);

by the

Object result = (o == null || o.subObject == null) ? defaultVlue : o.getSubObject().getDesiredValue();

Create method only if you can reuse it......

Upvotes: 1

Ruchira Gayan Ranaweera
Ruchira Gayan Ranaweera

Reputation: 35557

You can do something like this

public static Object  NullSafeCall(MyObject o,Object defaultValue){
    if ( o == null || o.getSubObject() == null)
    {
        return defaultValue;
    }
    else 
    {
        return o.getSubObject().getDesiredValue();
    }
}

Now you can call this method as follows

 Object result = NullSafeCall(o, defaultValue);

Upvotes: 0

Sebastian Redl
Sebastian Redl

Reputation: 71989

Not really, any code you would write this way would look horrible and/or use very slow reflection. Unless you use an actual Java preprocessor that can understand and change the code you've written.

A better (but associated with quite a bit of refactoring) approach would be to make sure that the values in question cannot possibly be null. For example, you could modify the individual accessors (getSubObject(), getDesiredValue()) to never return null in the first place: make them return default values. The accessors on the default values return default values in turn.

Upvotes: 1

Related Questions