如果我有以下功能,有两个选择
private MyObject findBlank() {
for (int i = 0; i < pieces.length; i++) {
if(pieces[i].isBlank()){
return pieces[i];
}
}
return null;
}
private MyObject findBlank() {
for (int i = 0; i < pieces.length; i++) {
if(pieces[i].isBlank()){
return pieces[i];
}
}
throw new NoSuchFieldError("No blank piece found!");
}
从这个方法我知道它应该总是返回一个对象其中一个'pieces'始终是isBlank() == true
,最后的返回null只是为了取悦编译器。既然是这种情况,如果它返回null我的代码无论如何都不会工作,这是正确的请抛出异常吗?
我的选择是:
我想我要问的是,这是抛出异常的正确位置吗?也就是说,如果遇到这种情况,我无能为力。这被归类为'例外'还是我应该检查我的方法返回什么(这使我的代码看起来很糟糕)。如果我知道它不应该返回null那么我应该抛出异常吗?
另外,我如何选择什么异常,或者扩展一个并抛出我自己的异常呢?
答案 0 :(得分:10)
我想我要问的是,这是抛出异常的正确位置吗?
如果是例外情况,那么是。如果找不到符合条件的任何内容的可能性预期那么情况不是例外,您应该返回null
。
答案 1 :(得分:4)
是的,您应该抛出RuntimeException
来表示不应发生的“例外”情况。 IllegalStateException
可能符合要求。确保包含一条消息,其中包含任何可以帮助您找到错误的信息。
答案 2 :(得分:4)
关于您的选择,问自己是否
null
)之后,让您的程序在某个时刻爆炸是个好主意吗?null
返回值,究竟会隐藏什么?我个人会选择2或3,这取决于我是否更喜欢问题2或3的答案。选项1肯定是一个坏主意,特别是如果它不应该发生。如果程序在函数返回后抛出NPE方式,那么您将很难确定null
来自何处。特别是如果它在你完成这个特定功能的几个月后发生。
如果您选择抛出异常,您会立即看到 出现问题的地方,您可以直接找到为什么出错了。返回null
并在调用函数中检查它也可以工作,但前提是你没有以静默方式失败,而是实际做了一些事情来正确处理问题。
答案 3 :(得分:1)
使用Null Object pattern可能是个好主意。
Provide an object as a surrogate for the lack of an object of a given type. The Null Object provides intelligent do nothing behavior, hiding the details from its collaborators
因此,在这种情况下,您不必使用异常或返回null。您始终可以返回预期的返回类型对象。诀窍是当你没有任何东西可以返回时,你可以返回与预期返回类型相同类型的null
,而不是返回Null object
或抛出异常。
此documentation有一些示例和说明。并且有类似的情况,通过设计模式解决。
public class CustomerFactory {
public static final String[] names = {"Rob", "Joe", "Julie"};
public static AbstractCustomer getCustomer(String name){
for (int i = 0; i < names.length; i++) {
if (names[i].equalsIgnoreCase(name)){
return new RealCustomer(name);
}
}
return new NullCustomer();
}
}
答案 4 :(得分:1)
除了大多数答案之外,我想指出,如果表现是您关注的问题,例外情况要慢于返回空白
看看这段代码:
class Main {
public static void main(String[] args) {
testException();
testNull();
}
public static void testException() {
long st = System.currentTimeMillis();
for(int i=0;i<10000000;i++) {
try{
exp();
} catch(Exception e) {
}
}
long et = System.currentTimeMillis();
System.out.println("Time taken with exceptions : "+(et-st));
}
public static void testNull() {
long st = System.currentTimeMillis();
for(int i=0;i<10000000;i++) {
returnNull();
}
long et = System.currentTimeMillis();
System.out.println("Time taken with null : "+(et-st));
}
public static void exp() throws Exception {
throw new Exception();
}
public static Object returnNull() {
return null;
}
}
我机器上的结果是:
Time taken with exceptions : 7526
Time taken with exceptions : 5
如果抛出异常是代码中的罕见情况并且不会经常发生,那么在这两种情况下所花费的时间几乎相同。
您必须权衡效果与可维护性/可读性。
详细了解here
答案 5 :(得分:1)
返回null大部分时间都会绘制从合同视图中丢失的信息,如果从生产者那里获取null,则消费者无法知道错误响应的原因是什么。
查看你的第一个代码,外部代码有两种情况得到NULLPointerException: 这些碎片是空的 这些碎片没有这样的元素
因此,返回null将导致外部代码误导以进一步操作,它将引发潜在的问题。
并讨论返回nullObject(非null)和异常之间的区别,主要区别是PROBABILITY,这意味着: 1.如果空情概率更高,它应该返回nullObject,以便所有外部代码可以/应该显式处理它们。 2.如果空情况的概率较小,为什么不抛出异常,以便最终调用函数可以直接处理它。
答案 6 :(得分:1)
我相信正确的答案取决于调用该方法的代码。有两种情况:
调用代码不确定对象是否存在,并且将具有处理特殊情况下不存在的代码。
调用代码确信该对象存在,并且如果不存在该对象,则逻辑上还会存在其他深层问题,在这种情况下,您所能做的就是放弃并报告错误。 / p>
在实践中,我经常使用命名约定来实现两者,以区分它们:
private MyObject findBlankOrNull() {
for (int i = 0; i < pieces.length; i++) {
if(pieces[i].isBlank()){
return pieces[i];
}
}
return null;
}
private MyObject findBlankOrFail() throws Exception {
MyObject obj = findBlankOrNull();
if (obj != null) {
return obj;
}
throw new NoSuchFieldError("No blank piece found!");
}
请注意,始终可以构造OnFail
版本来调用另一个版本,然后引发异常而不是返回null。本质上,您正在做的是插入Exception异常来代替return null,以确保不返回null,因此您不需要任何代码就可以在调用站点测试null。
我写了一篇有关该主题的博客文章:Return Null or Exception?,其中有更详细的介绍。
答案 7 :(得分:0)
应始终返回一个对象或返回null
和
该应用会在某些边缘情况下获得NullPointerException
这两者相互矛盾。
如果您确定自己已经pieces[i].isBlank()
,那么请IllegalStateException
否则请根据您的要求处理案件。
答案 8 :(得分:0)
如果数组应始终具有要返回的有效值,则应将异常作为回退引发。 (在你的例子中为2sd)
最终,您可以声明自己的异常类(Class)。
答案 9 :(得分:0)
我建议您使用我刚刚在another answer中谈到的Maybe
(也称为Option
)数据类型。
is available中的此数据类型Functional Java。
<强>用法:强>
private Option<MyObject> findBlank() {
for (int i = 0; i < pieces.length; i++) {
if(pieces[i].isBlank()){
return Option.some(pieces[i]);
}
}
return Option.none();
}
<强>旁注:强>
您的findBack
方法可以推广到一个将谓词作为参数的方法,并查找并返回满足它的第一个元素。
不出所料,Functional Java already has that as well。
我们暂时假设pieces
是fj.data.List
。然后您的方法可以重写为:
private Option<MyObject> findBlank() {
return pieces.find(new F1<MyObject, Boolean>() {
public Boolean f(MyObject p) {
return p.isBlank();
}
});
}
另一个旁注:
也许上面的代码看起来很粗糙。 IntelliJ IDEA's "closure folding" can be of some help here