1

是否可以将以下代码包装在可重用函数中?

编辑: 这只是一个例子,我想要一个适用于所有递归深度的工作解决方案

我想要的是生成以下代码:

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

通过调用类似的东西

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

第二个代码块只是一个想法,我不在乎它看起来如何,我想要的是,如果需要,我可以null在调用更深层次的函数之前避免所有检查......

注射可以有效地做到这一点,但没有其他/更简单的解决方案吗?以前从来没有看过注射...

EDIT2: 另一种语言的示例:http: //groovy.codehaus.org/Operators#Operators-SafeNavigationOperator

4

5 回答 5

1

Java8 有助于以我怀疑的良好性能获得最接近您的语法;

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

这可以通过这个实用程序类来完成;

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);
    }
}

遗憾的是,您需要为链中方法调用的每个数量定义一个单独的 eval(),因此您可能想要定义一些,但编译时类型安全且可与几乎任何调用/类型重用。

于 2013-07-25T14:18:47.477 回答
1

并非如此,您以这种方式编写的任何代码都会看起来很糟糕和/或使用非常缓慢的反射。除非您使用可以理解和更改您编写的代码的实际 Java 预处理器。

更好的(但与相当多的重构相关)方法是确保所讨论的值不可能为空。例如,您可以将各个访问器 ( getSubObject(), getDesiredValue()) 修改为从不返回 null:让它们返回默认值。默认值的访问器依次返回默认值。

于 2013-07-25T12:22:58.047 回答
0

我建议只是更换

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

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

仅当您可以重用它时才创建方法......

于 2013-07-25T12:50:07.793 回答
0

你想要的是不可能的。理解使用这种语法是很重要的:在任何控制传递给函数/方法从而引发异常之前Object result = NullSafeCall(o.getSubObject().getSubObject() ...);,该部分o.getSubObject().getSubObject()将被评估。

在执行此类代码之前,需要具有某种类型的上下文。我能想到的最接近这个的,可以使用匿名内部类来完成,如下例所示:

// 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
}
于 2013-07-25T13:29:30.433 回答
0

你可以做这样的事情

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

现在您可以按如下方式调用此方法

 Object result = NullSafeCall(o, defaultValue);
于 2013-07-25T12:24:46.650 回答