2011-03-23 64 views
22

爲什麼我們不能在公共方法中使用斷言?爲什麼我們不能在公共方法中使用斷言?

我是在哪裏讀

「的斷言公共 方法不適當的,因爲該方法保證 ,它會一直執行 參數的檢查。公共方法必須 檢查它的參數是否 斷言是有效的,此外, 斷言構造不會拋出指定類型的 例外,它只能拋出AssertionError「。

那麼,是否也適用於私人方法呢?
我完全不明白上述說法

+10

「can not」和「should not」之間有區別 – 2011-03-23 11:59:01

+3

您是否有此引文的來源? – jmg 2011-05-12 08:14:51

+0

@jmg - 我在下面的答案中添加了源代碼和精確引用。它禁止在公開方法中用於論證檢查的斷言。 – 2011-05-17 22:29:57

回答

24

的重要區別是你是否相信一個不正確的值是

a)一個編程錯誤,這應該是固定的代碼的結果。

b)在代碼中無法防止的輸入錯誤,而是需要在運行時處理。

對於第一種情況,您應該使用斷言,因爲程序代碼需要修復。如果它的後面的情況,你應該使用適當的運行時或檢查異常。


恕我直言斷言用於檢測編程錯誤,而不是用戶/外部輸入。也許作者混淆公共方法作爲外部輸入時,你會有公共方法,不被外部輸入調用。

我會使用斷言來檢查參數來檢測編程錯誤。恕我直言,這往往是他們的最佳用途。通過比較的私人方法只能由同一類中的代碼調用,並且您應該期望它們能很好地進行單元測試,並且可能的訪問/用途有限。

我發現你更有可能通過公共接口產生編程錯誤,因爲不同的人做出不同的假設(斷言是記錄和檢查假設的好方法)內部檢查並不像你期望的那樣有用程序員如果沒有編寫完整的內部代碼庫,就可以訪問內部代碼。

1

一般來說聽起來很合理。雖然在某些情況下這可能有用。

考慮我們可能想對我們知道存在的元素執行database update操作。那麼它可能是,看是否成功例程,例如有用,:

public void update(Object o) { 
    int nUpdatedObjects = dao.update(o); 
    assert(nUpdatedObjects == 1) 
} 

在這種情況下它用於validate使用fail fast principledao層。

+1

同意這種情況是有道理的;我想引用的部分可能是指使用'assert()'來驗證方法的參數是否合理。 (這是很有用的,但只是'assert()'有用的一個子集,正如你指出的那樣。:) – sarnold 2011-03-23 11:54:20

1

斷言是用於調試;公共方法通常不應該通過調試斷言來驗證事物,而是通過進行適當的參數檢查並拋出相應的異常。如果要驗證內部對象狀態,但不驗證參數,則可以使用它。

+3

-1「斷言是debugginng」。 – Ingo 2011-03-23 12:11:43

+1

@Ingo:考慮到斷言通常在生產版本中被禁用,這是一個合理的陳述。 – geekosaur 2011-03-23 12:13:51

+2

我不同意。斷言是爲了確保不變量,恕我直言。當然,在生產代碼中,人們應該確信沒有違規行爲。 – Ingo 2011-03-23 12:22:39

0

這個想法是,你不知道誰會使用你的公共方法。所以你必須用正常的檢查來防止不正確的使用。

另一方面,私人方法應該由您當前團隊的開發人員完全使用,所以檢查不是(強制性的)(但仍建議恕我直言)。

因此,檢查私有方法的論證有效性斷言應該是足夠的。

3

就目前而言,你引用的句子是無稽之談,我相信。

可以肯定,assert並非用於驗證參數。

但是在每個非平凡的程序中都有(或者應該是)許多不變式,這就是斷言可能派上用場的地方。如果您可以在斷言中表達不變量,請這樣做,無論該方法是否公開。

然後,以下情況之一會發生:

一)一切都很好。
b)在運行時,程序會失敗並顯示未完成的斷言。如果斷言是正確的,那麼不變量就會被違反,並且您有機會找出原因並修復錯誤(或重新考慮您的設計)。

15

斷言不應該用於檢查公共方法的參數有以下原因:

  • 斷言可以被禁用和參數的檢查一樣,它們的方法與它的調用者的合同的一部分從未被禁用
  • 斷言失敗不會爲無效參數拋出適當的異常。

例子:

/** 
    * @throws ArithmeticException if divisor is zero 
    */ 
    public void int divide(int divisor) { 
     if (divisor == 0) { 
      throw new ArithmeticException("Cannot divide by zero"); 
     } 
     ... 
    } 

如果你使用斷言這可以被關閉,它會拋出一個AssertionFailedException,這是無益的,無信息。

1

我給出的答案並不完全在這一點上。當然你可以在公共方法中使用斷言(或者你喜歡的任何地方)。

重點在於你應該做什麼或不做什麼。我自己完全理解別人對你何時應該或不應該使用斷言的迴應。

但我必須承認,我永遠不會使用斷言,並且我很少會在代碼中看到斷言。我只工作了幾年,但在我工作的4個完全不同的公司中,代碼中沒有斷言。無論是預訂航班,航天器控制中心,管理大型超市的軟件還是錯誤跟蹤器,它都是超過1000萬行的代碼Web應用程序。他們都沒有使用斷言。所有公司都有不同的需求和方法。沒有使用斷言。

對我而言,原因很簡單。這裏的人們說斷言是用於調試的。沒關係。而且你可以停用它們以提高速度。那也好...起初。程序越複雜,調試的時間就越多。即使有100%的代碼覆蓋率,即使進行了廣泛的集成和驗證測試,也會發現一些錯誤,但只能在生產環境中找到它們。僅僅因爲你的用戶比你更多地使用你的應用程序。他們不會像你一樣使用它。

這很有趣,因爲在生產日誌中,我們不斷看到來自代碼蹤跡是這樣的:

catch (MyException e) { 
    logger.war("This should never happen",e); 
} 

這是什麼意思是,你永遠不知道會發生在生產什麼。

而且,如果你有機會做一個檢查,那麼做。當然,日誌評論比這裏有用的更有趣,最好讓異常彈出。

在所有情況下,不要將其作爲生產中將被禁用的斷言。因爲它是無用的。使它成爲引發異常的正常代碼。確保它在適當的時候被記錄。確保在用戶界面上顯示錯誤。並確保您能夠獲取異常和日誌進行調查。

重要的是有一天或其他一些用戶會做出使警告彈出的事情。不管是因爲代碼寫得不好或者其他原因,你都會看到它。這意味着,不要花2天的時間找到地獄中的原因,程序有這種奇怪的行爲,你可以在起點使用完整的堆棧跟蹤,並在2小時內糾正問題。

具有禁用斷言的檢查與根本沒有檢查相同。它是你必須編寫,閱讀和維護的代碼......沒有任何東西。我理解在生產斷言中放慢速度的整個表現論據。是的,在某些情況下,存在性能問題。在大多數情況下,無論如何,你幾乎什麼都得不到,並失去了寶貴的提示。

+0

我尊重你在說什麼。但是,斷言可以通過代碼快速分散,而不用考慮代碼覆蓋的性能或影響。我擔心只使用不變量的例外可能會導致更少的不變量被表達。表達不變量是有價值的,即使它們可以關閉。 – 2011-05-18 21:57:49

1

這大概是原始來源,從Java SE引導"Programming with assertions."

不要用斷言檢查的公共方法的 參數。 斷言是不合適的,因爲 方法保證它總是會執行 執行參數檢查。它必須檢查其參數 是否啓用了斷言。此外, 聲明構造不會拋出指定類型的 異常。它 只能拋出一個AssertionError。

這並不禁止在公共方法中的斷言。它禁止它們僅用於檢查公共方法參數。

斷言測試不變量。一個類控制發送到其私有方法的實際參數,並且可以保證不變量。一個類不控制發送到公共方法的實際參數,並且如果違反前置條件,即使斷言被關閉,也應該拋出異常。

有關何時使用聲明的更多細節是here

0

這個禁止只適用於公共接口。

http://download.oracle.com/javase/6/docs/technotes/guides/language/assert.html#preconditions

按照慣例,在公共方法的前提條件是由特定的扔,指定例外明確檢查執行。

基本上,約定是公共接口保證檢查先決條件並拋出特定的異常而不是AssertionError。

對於所有其他情況,斷言非常有價值,是「按合同編程」的基石。請參閱http://java.sun.com/developer/technicalArticles/JavaLP/assertions的一個很好的介紹。

  1. Java有一個原因unchecked異常 - 這是很多不應該普遍陷入災難性的失敗。任何內存分配都會拋出OutOfMemoryError。一個失敗的斷言(客戶代碼中的一個錯誤,爲我們的API提供了一個無效的參數)並不是一個災難。

  2. 確實斷言可以關閉。但是,這絕不應該這樣做。只是不要這樣做。如果你害怕正在運行你的代碼的人會關閉斷言,你總是可以創建一個你自己的無關的斷言類。使用斷言的原則是不變的。

  3. 關於斷言你應該考慮的唯一事情是你的接口上的性能契約。請注意,這也可能是一個「隱式」合同(即當明顯的實施應該非常快時,需要一分鐘時間就不在暗示的合同中)。因此,請確保在性能合同下驗證您的聲明是可接受的。

1

在公共方法中使用斷言沒有任何錯誤。它們可以用來檢查某些不變量(你相信是真的),關於你稱之爲方法的對象或類 - 事實上是真的。

例如,您可以在構建器的public build()方法中使用斷言,以確保構建器由我自己的內部代碼在該類中正確初始化(因爲我有一個數字爲它重載的構造函數)。

但是你永遠不應該做的是使用斷言檢查公共方法的自變量。一個重要的區別。我認爲這裏的其他答案已經足夠清楚地解釋了原因,所以我不會重複任何事情。

0

公共方法可以被任何人調用,並且不能控制什麼可以作爲參數值傳遞。

如果在公共方法中我們已經使用斷言驗證了輸入參數值,那麼如果斷言被禁用,那麼這些檢查(驗證)可能不會發生(或執行),並且我們會從方法執行。爲了避免這種不良結果,我們不應該使用斷言來驗證公共方法參數值。

現在你可能想到的問題是爲什麼使用斷言來驗證私有方法參數值?

那麼,原因是可以從它定義的類中調用私有方法(從實例方法或從靜態主方法)。類的開發人員知道私有方法的一切 - 它是什麼如何調用它以及要傳遞哪些參數值。因此可以使用斷言安全地驗證私有方法參數值。

相關問題