Java 若对象(或任何函数结果)为空,则调用函数应返回默认值

Java 若对象(或任何函数结果)为空,则调用函数应返回默认值,java,null,null-check,Java,Null,Null Check,是否可以将以下代码包装到可重用函数中 编辑:这只是一个示例,我想要一个适用于所有递归深度的工作解决方案 我想要的是生成以下代码: if (MyObject o == null || o.getSubObject() == null || o..getSubObject().getSubSubObject() == null /*|| ... */) return defaultValue; return o.getSubObject().getSubObjec

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

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

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

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);
seond代码块只是一个想法,我不在乎它看起来如何,我想要的是,如果需要,我可以在调用更深层的函数之前避免所有的
null
检查

注射可能做到这一点,但是否没有其他/更简单的解决方案?以前从未看过注射


EDIT2:另一种语言的示例:

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


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

您可以这样做

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

我建议换个新的

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

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

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

您想要的是不可能的。必须理解使用以下语法:
objectresult=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
}
//打算由匿名内部类实现
接口安全操作{
公共行政自由();
};
//安全执行操作的执行者
公共静态类NullSafeExecutor{
公共NullSafeExecutor(){}
公共T执行(T默认值,NullSafeOperation nso){
T结果=默认值;
试一试{
结果=nso.executeSafely();
}捕获(NullPointerException e){
//忽略
}
返回结果;
}
//实用工具方法创建一个新实例并一步执行
公共静态T执行操作(T defaultValue、NullSafeOperation nso){
NullSafeExecutor e=新的NullSafeExecutor();
T结果=e.execute(默认值,nso);
返回结果;
}
}
公共静态void main(字符串[]args){
最终字符串aNullString=null;
字符串结果=NullSafeExecutor.executeOperation(“MyDefault”,新的NullSafeOperation()){
@凌驾
公共字符串executeSafely(){
//试图对空字符串调用方法
//它将抛出NullPointerException,但它将被执行器捕获
返回aNullString.trim();
}
});
System.out.println(“Output=“+result);//prints:Output=MyDefault
}

Java8有助于以良好的性能最接近您的语法

//如果有任何内容返回null,则使用默认值5进行计算。
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);
    }
}
类可选{
公共静态Tdef eval(Tdef def,T输入,功能fn1,
功能(fn2)
{
如果(输入==null)返回def;
T1 res1=fn1.apply(输入);
如果(res1==null)返回def;
返回fn2。应用(res1);
}
}

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

谢谢,我知道这个特定的解决方案,我想要的是一个函数/预编译器,或者任何适用于所有类和所有深度的语法。。。所有对象的可重用解决方案…我对每个解决方案都感兴趣。。。这个问题出现的原因是一个android项目…这是一个解决方案,我知道。。。事实上,我不在乎这些函数是否返回null,我只想要一个默认值(甚至可能是null)作为结果,如果任何对象(无论哪个级别)为null。。。要避免NullPointerException。。。我只是想可能会有一个,就像你说的,例如预处理器解决方案或其他东西。。。在我的例子中,我正在访问一个抽象类的实例,它只能在特定的点上创建。。。在这一点之前,我不想无缘无故地创建一个空实例……类似这样:不幸的是,这是一种不同的语言。顺便说一句,我发现一篇博客文章提出了针对Java7的建议——显然它没有被接受。我也将此视为对java7的建议,但据我在那里读到的,它从未纳入其中。。。但这正是我想要的…这只是一个具体的解决方案(用它做一行)。。。不可重复使用。。。我编辑了我的主要帖子,以便更清楚地说明我想说什么。我知道这种语法是行不通的,它只显示了我想要的。。。您可以将语法更改为
NullSafeCall(“o.getSubObject().getDesiredValue()”,defaultValue)。。。这很有效。。。之后,我可以解析字符串和子函数,并检查它们的所有返回值(带有反射)。。。如前所述,我问题中的代码只是演示了我想要的…我理解。我只是想指出,如果没有上下文,那么这样的方法是不可能的。上面的解决方案提供了一个:代码被包装在一个内部类中。如您所说,使用字符串版本和反射提供了另一个c