2009-11-10 72 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