2012-06-03 93 views
5

如果我有以下功能,只有两个选择抛出一个异常或返回null

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!"); 
} 

从这个方法我知道这应该总是返回一个对象的“艺术品”的一个总是isBlank() == true,最后的返回null只是为了取悦编译器。既然是这样,而且我的代码无论如何都不会工作,如果它返回null,这是正确的请抛出一个异常?

我的选择是:

  1. 返回NULL和应用程序将在一些边缘情况
  2. 返回NULL得到一个NullPointerException,敷使用的方法与检查
  3. (myObject的!= NULL)抛出一个异常,在运行时会炸掉它

我想我问的是,这是抛出异常的正确位置?即如果它陷入局面,我无能为力。这是归类为“例外”,还是应该检查我的方法返回的是什么(这会使我的代码看起来很糟糕)。如果我知道它不应该返回null,那么我应该抛出异常吗?

另外,我将如何选择什么异常,或扩展一个并抛出自己的?

+0

为了帮助选择一个例外:http://wuhrr.wordpress.com/2007/11/22/java-exceptions-list/ – Blundell

+0

“既不”建议不吸引力? :-) – missingfaktor

+0

@missingfaktor我在Android中编码,所以不能引入其他重型框架 – Blundell

回答

4

关于你的选择,问问自己,如果

  1. 是否有你的程序在某些时候炸掉后,该方法返回一个意外的值(即null)一个好主意?
  2. 如果你掩盖了null返回值,究竟会隐藏什么?
  3. 仅仅因为存在错误的价值而立即爆炸是一个好主意吗?

就我个人而言,我会选择2或3,这取决于我是否更喜欢问题2或3的答案。选项1绝对不是一个好主意,尤其是如果它不应该发生的话。如果程序在返回函数后抛出NPE方式,则很难确定null的来源。特别是如果它在完成这个特定功能的几个月后发生。

如果您选择抛出一个异常,您可以立即看到其中出了问题,你可以直接去那里弄清楚为什么出了问题。返回null并且在调用函数中检查它也可以工作,但前提是你不会默默地失败,但实际上可以正确地处理问题。

4

是的,你应该抛出一个RuntimeException来表示一个不应该发生的“特殊”情况。 IllegalStateException可能符合法案。确保包含一条消息,其中包含任何可帮助您查找错误的信息。

+0

我不确定我是否同意“无法恢复”部分。 –

+0

@HovercraftFullOfEels - 你如何推荐它应该措词? –

+0

我会删除“你的程序无法恢复”部分。 –

10

我想我问的是,这是抛出异常的正确位置?

如果是例外的情况,那么是的。如果没有找到任何符合标准的可能性是预计那么情况不是例外,你应该返回null

0

应该总是返回一个对象返回NULL

应用程序将在一些边缘情况
这两个是矛盾得到了NullPointerException

如果你真的确定你alwasy有pieces[i].isBlank()再扔IllegalStateException

根据您的要求,否则处理的情况。

0

如果你的数组应该总是有一个有效值返回,你应该引发一个异常作为后备。 (在你的例子中为2sd)

最终,你可以声明你自己的类(异常)。

0

我会建议使用Maybe(也称为Option)数据类型,我刚刚在another answer前一段时间讨论过。

此数据类型is availableFunctional 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。我们假设piecesfj.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

+0

查找更多肉[这里](http://goo.gl/E7lQ7)。 – missingfaktor

0

可能是使用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(); 
    } 
} 
+0

https://www.cs.oberlin.edu/~jwalker/nullObjPattern/ – prime

0

除了大部分的答案,我想指出,如果性能是您的关心,然后,例外比返回null

这个代码看看方法要慢:

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

0

返回null大部分时间将吸引来自合同视图信息丢失,消费者可以不知道什么是如果生产得到空的错误响应的原因。

寻找你的第一个代码,在两个情况外码得到NullPointerException异常: 1个是空 2件没有这样的元素

因此返回null将错误导致的外代码为进一步操作,它将提出潜在的问题。

并讨论返回nullObject(not null)与异常之间的区别,主要区别是概率,意思是: 1.如果空情况的概率更大,则应返回nullObject,以便所有外层代码都可以/应该明确地处理它们。 2.如果空情况的概率较小,为什么不抛出异常,以便最终调用函数可以直接处理它。