2009-11-10 61 views
5

我聽到人們提醒,每個人都應該使用Iterator pattern控制迴路而不是拋出一個異常(這是它是如何在Python iterators完成)或使用Sentinel pattern,其中一個特殊的前哨值(通常null)返回指示迭代的結束。是否有任何理由避免Java中的哨兵模式?

最佳做法是否建議不要使用哨兵模式?如果是這樣,爲什麼? (而不是在Java 1.5中使用foreach語法)。

編輯: 代碼示例1 - 哨兵模式

Reader r = ...; 
for(int val = r.read(); val != -1; val = r.read()) { 
    doSomethingWith(val); 
} 

代碼示例2 - 迭代器模式

for(Iterator<Thing> it = getAnIterator() ; it.hasNext();) { 
    Thing t = it.next(); 
    doSomethingWith(t); 
} 
+0

你可能想要顯示你所問的三種循環模式中的每一種的例子。 – 2009-11-10 17:32:51

+0

沒有包含python的方式,提出控制流的異常不是我正在認真暗示的東西。 – 2009-11-10 17:49:41

+0

+1僅用於I/O for循環 - 我從來沒有見過這樣做。 – 2009-11-11 02:16:39

回答

15

與哨兵模式的問題是,它明確地設定排除標記值屬於有效元素的值。也就是說,如果你有一個可以有效地包含null的對象列表作爲元素,那麼使用null作爲標記值是失敗的。

9

例外只能用於「特殊」情況。結束或退出循環是正常的程序流程,並非特殊情況。因爲其他Java程序員可能需要維護您的代碼,所以您希望使用在社區中常見且衆所周知的模式和約定。如果他們這樣做,他們很可能期望看到迭代器,而不是哨兵模式。

+4

我同意這一原則,並建議遵循它。骯髒的祕密是異常拋出版本非常快,尤其是如果你使用緩存的異常單例。但我不會那樣做,除非我需要瘋狂的速度,我可以證明它速度更快。我在這裏提到它僅僅是因爲它很有趣。 – 2009-11-10 18:07:15

0

我沒有看到哨兵模式是如何不同,足以成爲自己的模式。我唯一的想法是,從流數據中確定停止值會很有用。然而,interator用「hasMore」方法要求來處理這個問題。

2

在JDK中使用Sentinel模式來讀取流,所以它不是聞所未聞的,但是使循環出來很尷尬。所有的解決方案都有一個迭代器沒有的負面因素。您的解決方案需要重複調​​用才能讀取(即代碼重複)。 while循環強制變量被聲明在循環範圍之外。其他替代方案會令人驚訝,難以遵循。

所以最後迭代器是一種默認值,應該只是出於某種原因而偏離。

4

我認爲它們都可以,但是Iterator在Java中更具慣用(尤其是如果你實際上有一個Iterable,你可以使用for-each循環代替它)。

您在Java中看到Sentinel版本的地方就是您在I/O代碼中編寫的情況。

+0

+1因爲指出並不存在涵蓋所有案例的硬性規定,每種模式都有其優缺點。 – MAK 2009-11-10 19:04:14

2

咒語是「說出你所做的,然後按照你的說法做。」

如果您測試返回的值是一個特殊值,那沒有說明您爲什麼測試它。在您的例子:

for(int val = r.read(); val != -1; val = r.read()) { 
    doSomethingWith(val); 
} 

這是否說「如果返回值永遠爲-1,我們可以跳過剩下的」,或者「如果返回值永遠是-1,發生了錯誤」,或者「如果返回的值是-1,則達到最終結果「?相反,hasNext是完全無歧義的。

順便說一句,我其實很喜歡foreachmap結構其他語言比顯式循環提供(或允許寫)更好。

0

「只能在」例外「情況下使用例外,結束或退出循環是正常的程序流程,而不是特殊情況。」

如果一個文件讀取成功一百萬次,並且只有最後一次它說「我找不到任何記錄」,那麼您不稱之爲「特殊」?

我沒有看到使用EOFExceptions進行控制流的問題(如果系統足夠強大以提高它們,而不是返回非常愚蠢的-1整數,表示「讀取了-1個字節」) 。你告訴我,如果以下內容是不可讀/不可維護的:

try { 
    r = readNext(...); 
    process(r); 
} catch (EOFException e) { 
    ... 
} 
+0

如果你不喜歡Sentinel,一個布爾方法比只捕獲一個while(true)塊的異常要好得多。 – Yishai 2009-11-11 02:09:33

+1

那麼,我希望達到退出條件'我找不到更多的記錄'並不例外。當這是例外,那麼你的程序是越野車。你必須分開「罕見」和「特殊」情況。無論多少文件讀取完成或無關緊要 - 這種情況並不例外。 – 2012-08-12 16:52:21