我有以下模式的代码:
return a().b().c().d().e();
现在由于这些方法中的每一个都可以返回null
,因此通常会对此进行测试:
if( (a()!=null) && (a().b() != null) && ....) {
return a().b().c().d().e();
} else {
return null;
}
(也许可以使用一些局部变量来避免重复调用)
我很想做:
try {
return a().b().c().d().e();
} catch (NullPointerException e) {
return null;
}
那被认为是不好的风格吗?效率低下?还是挺好的?
答案 0 :(得分:16)
不要这样做。与基本空检查相比,抛出和捕获异常相当昂贵。
您可能也有兴趣知道已经为未来版本的Java提出了语法,这将使这更简单。它会是这样的:
a()?.b()?.c()?.d()
“?”操作将是“。”的可选版本。运营商。如果LHS为null,则在该点返回null,而不是尝试评估RHS。正是你在寻找什么,但我担心它没有为Java 7做好准备。不知道Java 8的这个功能的状态。
答案 1 :(得分:5)
它被认为是不好的风格,因为异常应该代表异常条件,这些条件在正常执行期间不太可能出现并且表明出现了问题。使用异常检查对象是否为null使用此机制来检查更平凡的故障。正如康斯坦丁的帖子所提到的,使用异常也会有运行时间损失。此外,将所有错误包装在一个NullPointerException
中意味着您丢失了有关特别是错误的信息。哪个函数返回null
?这是由于正常错误,还是有更严重的事情发生?
此处您还没有考虑其他选项。而不是让a()
,b(),
等返回null
来表示错误,请考虑让他们抛出更详细的异常,解释为什么他们无法返回某些内容。如果由于网络连接中断而导致它们失败,请让它们抛出IOException
或类似内容。如果他们因为你的数组索引错误而失败,那么也要明确。
简而言之,如果您想使用异常,请使用它们来更精确地通知程序的其余部分发生了什么。这样,您可以采取更细粒度的纠正措施。
答案 2 :(得分:5)
通常,这行代码本身就很糟糕,忽略了null问题。请参阅"Law of Demeter" or "Principle of Least Knowledge"。
return a().b().c().d().e();
如果我无法控制a,b,c,d和e,我会重写以下内容。
if( (a()!=null) && (a().b() != null) && ....) {
return a().b().c().d().e();
} else {
return null;
}
就像这样,这仍然令人发指,但是当某些东西混乱并且我需要读取堆栈跟踪时更有用。
B b = a.a();
if(b == null)
{
return null;
}
C c = b.b();
if(c == null)
{
return null;
}
D d = c.c();
if(d == null)
{
return null;
}
return d.d();
不,抓住NullPointerException
并不恰当。这有点像在for
块中包裹try
循环以捕获ArrayIndexOutOfBoundsException
。
如果这应该是fluent API,其中链接是一个强度和目标,那么它永远不应该返回空值。
答案 3 :(得分:2)
我不这样做主要是因为如果a()
或b()
或c()
等有一个导致它们抛出NullPointerException的错误?在那种情况下,你会抓住它并继续前进,而你却不应该这样做。
答案 4 :(得分:2)
更改方法,使它们不返回null或避免链接可返回null的方法。
答案 5 :(得分:1)
不是返回 null ,而是让每个人返回NullObject或其他东西。阅读Null Object Pattern。