2011-05-12 175 views
25
/** 
    * Returns the foo with the matching id in this list 
    * 
    * @param id the id of the foo to return 
    * @return the foo with the matching id in this list 
    */ 
    public Foo getFoo(int id) 
    { 
     for (Foo foo : list) 
     { 
      if (foo.getID() == id) 
      { 
       return foo; 
      } 
     } 

     return null; 
    } 

而不是返回null如果找不到foo,我应该throwexception?这有什么关系,并且有关于这个问题的“最佳实践”成语吗?顺便说一句,我知道我的例子有点做作,但我希望你能明白...替代返回NULL

谢谢。

编辑

更改代码来获得Foo基于ID为了更好地说明一个真实世界的场景。

+2

在某处有一个关于语言设计者的评论,他说他希望自己从不介绍null值。我不记得他的理由是什么。 – 2011-05-12 16:41:07

+4

@James P:那是CAR Hoare,这是一个报价:http://lambda-the-ultimate.org/node/3186 – 2011-05-12 17:59:47

+1

你可以使用NULL OBJECT PATTERN。检查是否符合您的要求http://en.wikipedia.org/wiki/Null_Object_pattern 警告... 应认真使用此模式,因为它可以使错误/错误显示为正常程序执行。[5] – 2011-05-13 09:25:02

回答

21

返回null不仅更简单处理,性能也更好。必须使用例外情况处理例外个案。

+0

这是一个重要的观点。如果事先不知道它是否包含Foo,那么null通常会更好。如果您始终认为Foo在列表中,那么例外可能更合适。 – DHall 2011-05-12 17:38:56

+2

我不同意。从空值返回和检查通常是一种气味。空对象模式可以很好地帮助。 – Finglas 2011-05-15 17:10:50

+2

让我想起有效的Java项目之一:尽可能避免null(http://www.javapractices.com/topic/TopicAction.do;jsessionid=7EE954B4960C1D08A5C839EB018D24EE?Id=134) – obaqueiro 2011-05-30 11:41:56

4

我更喜欢返回null。从方法返回这是一个非常好的结果,并且调用该方法的代码应该适当地处理空值。这可能意味着在你的调用代码中抛出一个异常,但我不会用这种方法来做。

这样,如果其他人想要调用你的方法,他们可以处理空值,如果他们选择不同。如果你抛出异常,它可能会迫使另一个程序员改变他们的代码的方式不同于他们的意图。

当然,在某些情况下,如果某些内容为null(例如,连接对象或类似的东西,实际上您需要有一个值,并且如果您没有这意味着什么是错的)。但是,作为一个经验法则,在大多数情况下你应该可以返回null。

+0

如果它确实返回'null',我应该记录这个地方代码?作为一个额外的评论,也许呢? – mre 2011-05-12 16:23:55

+0

如果您以后觉得这可能是一个混乱点,您可以。我认为你应该总是期望一个方法可以返回一个空值并在你的代码中适当地处理它。 – 2011-05-12 16:24:58

+2

你应该在Javadoc的'@ return'部分提及它。 – 2011-05-12 16:25:01

3

最好的事情就是在Javadoc说null是没有找到匹配时返回。

另一种方法可能是返回一个可能为空的匹配列​​表(并且可能有多个匹配)。但是我不喜欢这种方法。

另一种方法可能是返回Foo值类型的NULL_FOO。

我宁愿只是返回null。

解决此问题的一种方法是查看您将如何处理值并丰富该函数,以便返回的值在方法中使用并且不会返回。例如如果你打算用这个值调用一个方法,只需在函数中调用它来避免返回任何东西。

+0

Foo类型的NULL_FOO是[空对象模式](http://en.wikipedia.org/wiki/Null_Object_pattern) – MarkOfHall 2011-05-12 17:03:19

1

majory它取决于场景。如果您的应用程序本身就是此方法的生产者和使用者,那么它完全取决于您决定要做什么,否则您需要根据方法和客户端需求的使用情况来决定。

5

返回null很好,如果它被记录为有效结果。

另一种选择是空对象模式。那就是 - Foo实例,它不具有任何数据:

public class Foo { 
    public static final Foo NULL_FOO = new Foo(); 
} 

,并返回它来代替。

+2

这看起来像是隐藏错误的好方法。 – 2011-05-12 16:27:28

+0

@Isaac:你的意思是无声的错误,因为把一个接头留空? – 2011-05-12 16:49:28

+0

@Bozho:如何使用它?你只是在方法中返回一个Foo.NULL_FOO? – 2011-05-12 16:53:22

1

返回null是完全可以接受的。我会多出几十个按键,并记录在JavaDoc中返回null的可能性。

抛出checked checked意味着你必须在你的方法被调用的任何地方尝试/捕获或重新抛出异常。一个未经检查的例外,尤其是NPE以外的任何事情,都会让人感到意外。

1

在这种情况下,由于您正在定义一个存取器,它应该返回null。如果这是另一种方法,这种方法应该保证非空响应,则例外情况会更合适。

作为一个侧面说明,虽然,而不是调用示例方法一个吸气剂,它可能是更合适的名称它像Foo findFoo(Foo f)因为你搜索,而不是只是得到。

4

如果可以,最好避免出现异常,但有时您不能。在这种情况下,如果您在列表中存储了null?你无法分辨'发现null'和'找不到你想要的'之间的区别。

有一种模式,它叫做Option Types,它在Scala中用得很多。你要么返回一个容器的物品,要么是一个说'我是空的'类的容器。该wiki文章将提供更好的图片。

你也可以有一个'在收集中存在吗?'方法返回一个bool,然后从上面的代码中抛出一个异常,如果你没有先检查。


而只是一个评论完全无关你的实际问题。如果你实现了equals,那么只有在两个对象实际上被认为是相等的情况下它才会返回true。因此,上面的代码必须始终返回您传递给它的对象!

+0

看到我的编辑,谢谢! :) – mre 2011-05-12 16:37:46

+1

我只是想我会提到它。我知道它与你的实际问题无关。 – Joe 2011-05-12 16:42:45

11

我想说这取决于你的方法的语义。

foo几乎总是在列表中找到? (例如,如果它是一个拥有有限数量对象的缓存)。如果是这样,那么找不到可能意味着出现了问题 - 例如某些应用程序初始化失败,或者密钥无效 - 并且异常可能是合理的。

但是,在大多数情况下,我会返回null。也许客户知道对象可能不在那里,并且有编码逻辑来处理这种情况;如果你使用了一个例外,那么这段代码将难于阅读,理解和维护。

一些API实际上提供了两种方法:一个可能返回null的find方法,以及一个抛出异常的getload方法。

嗯...有疑问时,宁可有利于空:)

+0

用于'find'的+1。我更喜欢那个约定,因为'find'意味着这个项目可能会丢失。另一方面'get'意味着调用者期望一个项目被返回,如果它不在那里,则可能有错误。 – ollb 2011-05-14 15:52:03

1

的我认为这是一个品味的问题,在这种情况下,它也取决于是否列表可能包含空值。如果列表可能包含空值,那么null也将是一个有效的方法参数,并且您需要区分返回null(例如null传递,找到并返回)或告诉方法调用方传递null值为而不是找到。

1

这可能不会直接回答你的问题,但它来自我从类似主题的Stackoverflow成员获得的一些评论。

而不是找到foo时返回null,我应该抛出异常吗?这有什么关系,并且有关于这个问题的“最佳实践”成语吗?顺便说一句,我知道我的例子有点做作,但我希望你明白......“

从我收集的情况来看,异常应该从一个方法抛出,当异常涉及一个参数例如,一个接受File实例的方法会抛出一个NullPointerException异常或一个IOException异常,这是因为调用者和被调用者之间存在一个合约,即调用者应该发送有效对象并在它们无效时予以照顾

另外,你需要决定是否处理前置和后置条件,你可以在方法的开始处放置一个警戒来处理参数,这样可以节省很多代码,但有些人认为这是一个不正确的appr因为在UI中应该事先做一些验证。

要完成,如果意图检索单个实例,则返回空对象是完全有效的。这是为了解释一个对象没有被发现或不存在。当涉及到一组对象时,我认为约定只是返回一个空的Collection/List。

0

我想说这取决于您的应用程序以及如何使用该方法。

  1. 如果您期望“未找到”结果频繁发生,可能会对性能产生负面影响*,则返回null,然后在调用者中检查它。
  2. 如果“找不到”结果会比较少见,或者会导致您的应用放弃请求,那么抛出异常就没问题。例外可以使你的代码更容易阅读,因为你可以保证成功返回会产生一个对象,所以你不必对它进行空值检查。

我同意异常应该用于特殊条件,这是错误条件的超集。我也采用了Spring/Hibernate对非检查异常的偏好,避免了繁琐的try/catch逻辑。

*使用异常与返回null没有太大的性能开销。我只是做了一个快速测试,它需要4ms调用一百万次返回null的方法,而另一个方法只有535ms会抛出一个异常。

0

另一个角度来看我有没有在其他的答案阅读如下:

是否list包含null“的Foo S'如果是这种情况,则不知道该ID是否被发现,或者是否与null有关。在这种情况下:

  • 抛出列表未找到的例外;
  • 将结果包装在另一个对象中(例如SearchResult,它告诉你该对象是否被找到,它是关联的id,它是结果,或者如果没有找到它,结果是否)。
  • 创建方法existsFoo(int id)

每个解决方案都有它自己的问题,这取决于使用哪种情况:

  • 正如其他人所指出的,Exception s为例外;
  • 每次您想要重新搜索时,都必须分配一个包装SearchResult。包装可以制成可变,但是这会带来很多新的困难和问题;
  • existsFoo必须搜索使钥匙存在或不知道的成本加倍的列表。

一般来说,我可以说:

  • 是一个ID 未找到例外?使用IllegalArgumentException;
  • 将结果传递给其他类,用作对象吗?使用包装,例如SearchResult;
  • 是否与getFoo只检查它是否为空(它是否存在)?使用另一种方法,existsFoo
0

尽管我同意null的编码是简单易用的样板程序员调节,但它并没有增加复杂性引入的价值。总是假设非空引用使代码略少的更清洁逻辑 - 您仍然必须测试失败。

注释excerpt below将帮助您不至于陷入旧的方式...

使用@Nullable

为了消除你的代码库NullPointerExceptions,你必须 纪律有关空引用。我们通过以下方式获得了成功 并执行了一条简单规则:

每个参数都是非空的,除非明确指定。

番石榴:谷歌核心库Java和JSR-305有简单的API 得到一个空值在控制之下。 Preconditions.checkNotNull可用于 对快速失败,如果一个空引用被发现,并@Nullable可用于 标注的参数,允许空值:

import static com.google.common.base.Preconditions.checkNotNull; 
import static javax.annotation.Nullable; 

public class Person { 
    ... 

    public Person(String firstName, String lastName, @Nullable Phone phone) { 
    this.firstName = checkNotNull(firstName, "firstName"); 
    this.lastName = checkNotNull(lastName, "lastName"); 
    this.phone = phone; 
    } 

如果空是你的类是允许的,你可以用@Nullable ...注解字段或 参数...使用任何@Nullable注释,如 edu.umd.cs.findbugs.annotations.Nullable或javax.annotation.Nullable。

0

这是一个老问题,但我没有找到番石榴的Optional类这里所说的也JDK的Optional(从Java 8)有异曲同工之妙,有更多的功能。

This article是一个很好的概述使用番石榴的可选原因。我强烈建议阅读它。

下面是摘录:

有什么意义?

除了提供可读性增加来自给出空名称 名称,可选的最大优点是它的防白痴。它 强迫你积极思考缺席的情况下,如果你想要你的 程序根本编译,因为你必须积极打开 可选的和处理该案件。 Null使得令人不安的是容易让 简单地忘记了事情,虽然FindBugs有帮助,但我们认为它不会解决问题。

当您返回可能或可能不存在的值时,这尤其重要。您(和其他人)更有可能忘记 other.method(a,b)可能会返回空值,而您可能会忘记在执行other.method时可能为null。 返回可选使得呼叫者不可能忘记 的情况,因为它们必须自己解开对象以便其代码 进行编译。

我个人认为,如果这很重要的话,返回null在像Java这样已经冗长的语言中并不那么可怕。该方法的签名有时尖叫,可能会有某种类型的空类型的结果,并且使用Optional不会在语义上添加任何东西。例如:

public Point2D intersect(Line line) 

或者在通过键在地图中查找值的方法中。

如果我们调用这样一个方法并对结果执行空检查,那很明显发生了什么(检查并行行或找不到关键字)。我希望返回null以免膨胀我的代码。

我总是将它记录在javadoc中。