我的代码如下:
obj1 = SomeObject.method1();
if (obj1 != null) {
obj2 = obj1.method2();
if (obj2 != null) {
obj3 = obj2.method3();
if (obj3 != null) {
............
return objN.methodM();
}
}
}
....
我有近10步。它似乎非常脆弱且容易出错。有没有更好的方法来检查空链方法?
感谢。
答案 0 :(得分:4)
为了更好地回答这个问题,需要更多的背景。
例如,在某些情况下,我主张将内部if
语句分解为自己的方法,遵循“每个方法应该做一件事,完全正确”。在这种情况下,调用方法并检查null 是那一件事:如果它为null,则返回(或抛出,具体取决于您的实际需要)。如果不是,则调用下一个方法。
最终我怀疑这是一个设计问题,但是如果没有深入了解正在解决的问题,解决方案是不可知的。
就目前而言,这一段代码需要深入了解(我怀疑的)多重职责,这意味着几乎在所有情况下,都需要新类,新模式,新接口或某些组合来实现这两者。干净,易懂。
答案 1 :(得分:3)
像
一样写obj1 = SomeObject.method1();
if (obj1 == null)
return;
obj2 = obj1.method2();
if (obj2 == null)
return;
等。作为C开发人员,这是一种非常常见的范例,并且非常常见。如果无法将代码转换为此平坦流程,那么无论代码使用何种语言,您的代码都需要首先进行重构。
将return
替换为您实际执行的任何操作,如果这些操作失败,无论是return null
,throw
例外等等 - 您已省略了该部分内容代码但它应该是相同的逻辑。
答案 2 :(得分:3)
我们可以使用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
}
答案 3 :(得分:2)
这是java中null
引用的常见问题。
我更喜欢与&&
链接:
if (obj1 != null && obj1.method1() != null && obj1.method1().method2() != null)
答案 4 :(得分:2)
我知道这个问题已经回答了here。特别是关于Null Object Pattern的第二个问题。
答案 5 :(得分:2)
您可以使用 java.util.Optional.map(..)
来链接这些检查:
return Optional.ofNullable(SomeObject.method1())
.map(SomeObject2::method2)
.map(SomeObject3::method3)
// ....
.map(SomeObjectM::methodM)
.orElse(null);
答案 6 :(得分: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;
不要忘记将所有obj
初始化为null
。
答案 7 :(得分: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
答案 8 :(得分:1)
对于没有参数的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>();
答案 9 :(得分:1)
如果您使用的是Java 8或更高版本,请考虑使用Optional
:
答案 10 :(得分:0)
您可以使用try / catch链接它们并包围所有内容并捕获NPE。
像这样:
try
{
Object result = SomeObject.method1().method2().methodN();
return result;
}
catch(NullPointerException ex)
{
// Do the errorhandling here.
}
除此之外我@Neil的评论:首先尝试避免使用这种链条。
投票显示非常有争议。我想确保理解,我实际上推荐这个
这样做有很多副作用,应该一般避免。 我只是把它扔进讨论 for OPs特殊情况,只有作为实现目标的一种方法,如果不可能的话!
如果有人认为他需要这样做:请阅读评论中可能存在的陷阱!
答案 11 :(得分:0)
如果你想要如此信任源对象,你打算将它们中的六个链接在一起,那么只需继续信任它们并在它们被抛出时捕获异常 - 希望很少。
但是,如果您决定不信任您的源对象,那么您有两个选择:在任何地方添加强制性“!= null”检查并且不链接他们的方法......
或者返回并更改源对象类并在根目录中添加更好的空值处理。您可以手动执行(例如,在setter中使用null检查),或者您可以使用Optional中的Java 8类(如果您不使用Java 8,则使用Optional in Google's Guava ),它提供了一种固有的空处理设计模式,可以帮助您在引入不需要的空值时做出反应,而不是等待一些不良消费者在以后遇到它们。