2011-05-12 84 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中。