9

我有如下代码:

obj1 = SomeObject.method1();
if (obj1 != null) {
  obj2 = obj1.method2();
  if (obj2 != null) {
     obj3 = obj2.method3();
     if (obj3 != null) {
              ............


     return objN.methodM();

   }
  }
 }
....

我有近 10 个步骤。它看起来非常脆弱且容易出错。有没有更好的方法来检查空链方法?

谢谢。

4

12 回答 12

6

您可以使用java.util.Optional.map(..)链接这些检查:

return Optional.ofNullable(SomeObject.method1())
        .map(SomeObject2::method2)
        .map(SomeObject3::method3)
        // ....
        .map(SomeObjectM::methodM)
        .orElse(null);
于 2021-04-22T15:55:30.977 回答
5

要很好地回答这个问题,需要更多的上下文。

例如,在某些情况下,我主张将内部if语句分解为它们自己的方法,遵循“每个方法应该完全正确地做一件事情”。在这种情况下,调用该方法并检查 null一件事:如果它为 null,则返回(或抛出,取决于您的实际需要)。如果不是,它会调用下一个方法。

最终我怀疑这是一个设计问题,但如果不深入了解正在解决的问题,则无法知道解决方案。

就目前而言,这一段代码需要深入了解(我怀疑是)多种职责,这意味着在几乎所有情况下,都需要新类、新模式、新接口或某种组合来使这两者都干净,并且可以理解的。

于 2013-01-21T16:13:30.840 回答
4

我们可以使用 Java8 功能接口方法。

@FunctionalInterface
public interface ObjectValue<V> {
    V get();
}

static <V> V getObjectValue(ObjectValue<V> objectValue)  {
    try {
        return objectValue.get();
    } catch (NullPointerException npe) {
        return null;
    }
}

Object obj = getObjectValue(() -> objectA.getObjectB().getObjectC().getObjectD());
if(Objects.nonNull(obj)) {
//do the operation
}
于 2017-07-26T07:09:01.513 回答
3

像这样写

obj1 = SomeObject.method1();
if (obj1 == null) 
    return;
 obj2 = obj1.method2();
 if (obj2 == null) 
    return;

等等。作为 C 开发人员,这是一个非常常见的范例,并且非常普遍。如果无法将您的代码转换为这种扁平化流程,那么您的代码首先需要重构,无论它以何种语言存在。

在这些失败的情况下替换return为您实际执行的任何操作,无论是return nullthrow异常等 - 您已经省略了代码的那部分,但它应该是相同的逻辑。

于 2013-01-21T15:57:42.023 回答
2

null这是java中引用的常见问题。

我更喜欢链接&&

if (obj1 != null && obj1.method1() != null && obj1.method1().method2() != null)
于 2013-01-21T15:56:03.183 回答
2

我想这种问题已经在这里得到了回答。尤其是关于Null Object Pattern的第二个问题。

于 2013-01-21T16:13:24.957 回答
1

您可以链接它们并用 try/catch 包围所有内容并捕获 NPE。

像这样:

try
{
    Object result = SomeObject.method1().method2().methodN();
    return result;
}
catch(NullPointerException ex)
{
     // Do the errorhandling here.
}

除此之外,我对@Neil 的评论表示赞同:首先尝试避免这种链条。

编辑:

投票表明,这是非常有争议的。我想确保它被理解,我实际上并不推荐这个!

像这样进行有很多副作用,通常应该避免。我只是将其用于讨论OP 的特殊情况,如果不可能的话,只是作为实现目标的一种方法!

如果有人觉得他需要这样做:请阅读评论以了解可能的陷阱!

于 2013-01-21T15:53:57.683 回答
1

尝试这样格式化:

obj1 = SomeObject.method1();
if (obj1 != null) {
   obj2 = obj1.method2();
}
if (obj2 != null) {
    obj3 = obj2.method3();
}
if (obj3 != null) {
          ............
}

if (objN != null) {
   return objN.methodM();
}
return null;

不要忘记将所有objs 初始化为null

于 2013-01-21T15:57:53.653 回答
1
obj1 = SomeObject.method1();
if (obj1 == null) throw new IllegalArgumentException("...");

obj2 = obj1.method2();
if (obj2 == null) throw new IllegalArgumentException("...");

obj3 = obj2.method3();
if (obj3 == null) throw new IllegalArgumentException("...");

if (objN != null) {
   return objN.methodM();
}

更多讨论here

于 2013-01-21T16:02:58.363 回答
1

如果您使用的是 Java 8 或更高版本,请考虑Optional

于 2020-10-09T21:55:36.787 回答
0

如果您希望如此信任您的源对象,以至于您计划将其中六个链接在一起,那么只需继续信任它们并在抛出异常时捕获异常 - 希望很少。

但是,如果您决定不信任您的源对象,那么您有两个选择:在任何地方添加强制“!= null”检查并且不要链接它们的方法......

或者返回并更改您的源对象类并在根处添加更好的空处理。您可以手动完成(例如,在 setter 中使用 null 检查),或者您可以使用 Java 8 中的Optional(如果您不在 Java 8 上,则可以使用Google 的 Guava 中的 Optional ),它提供了一个自以为是的 null-处理设计模式以帮助您在引入不需要的空值时对其做出反应,而不是等待一些可怜的消费者稍后遇到它们。

于 2015-07-22T20:39:05.723 回答
0

对于没有参数的 getter 方法,试试这个:

Util.isNull(person, "getDetails().iterator().next().getName().getFullName()")

在大多数情况下,它运作良好。基本上,它是尝试使用java反射逐层做空检查,直到到达最后一个getter方法,因为我们对反射做了很多缓存,所以代码在生产中运行良好。请检查下面的代码。

public static boolean isNull(Object obj, String methods) {
    if (Util.isNull(obj)) {
        return true;
    }
    if (methods == null || methods.isEmpty()) {
        return false;
    }
    String[] A = methods.split("\\.");
    List<String> list = new ArrayList<String>();
    for (String str : A) {
        list.add(str.substring(0, str.indexOf("(")).trim());
    }
    return isNullReflect(obj, list);
}
public static boolean isNullReflect(Object obj, List<String> methods) {
    if (Util.isNull(obj)) {
        return true;
    }
    if (methods.size() == 0) {
        return obj == null;
    }
    Class<?> className = Util.getClass(obj);
    try {
        Method method = Util.getMethod(className.getName(), methods.remove(0), null, className);
        method.setAccessible(true);
        if (method.getName().equals("next")
                && !Util.isNull(Util.getMethod(className.getName(), "hasNext", null, className))) {
            if (!((Iterator<?>) (obj)).hasNext()) {
                return true;
            }
        }
        try {
            return isNullReflect(method.invoke(obj), methods);
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    } catch (SecurityException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return false;
}


public static Boolean isNull(Object object) {
    return null == object;
}

public static Method getMethod(String className, String methodName, Class<?>[] classArray, Class<?> classObj) {
    // long a = System.nanoTime();
    StringBuilder sb = new StringBuilder();
    sb.append(className);
    sb.append(methodName);
    if (classArray != null) {
        for (Class<?> name : classArray) {
            sb.append(name.getName());
        }
    }
    String methodKey = sb.toString();
    Method result = null;
    if (methodMap.containsKey(methodKey)) {
        return methodMap.get(methodKey);
    } else {
        try {
            if (classArray != null && classArray.length > 0) {
                result = classObj.getMethod(methodName, classArray);
            } else {
                result = classObj.getMethod(methodName);
            }
            methodMap.put(methodKey, result);
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    // long b = System.nanoTime();
    // counter += (b - a);
    return result;
}
    private static Map<String, Method> methodMap = new ConcurrentHashMap<String, Method>();
于 2016-04-17T22:36:34.210 回答