Javaexception处理 – 样式

从历史上看,我总是编写我的exception处理代码,如下所示:

Cursor cursor = null; try { cursor = db.openCursor(null, null); // do stuff } finally { if (cursor != null) cursor.close(); } 

但最近,出于可读性和懒惰的原因,我已经开始这样做了:

  Cursor cursor = db.openCursor(null, null); try { // do stuff } finally { cursor.close(); } 

从try-catch-finally块中分配游标(jdbc句柄,无论如何)是错误的吗?

除非JVM真正炸毁了任务,或者在任务块中的任务和第一行之间,我不确定我的旧样式是否提供任何额外的值,第二个肯定更具可读性和简洁性。 文献通常总是采用第一种风格。

编辑 – 假设我很高兴openCursor抛出的任何exception,同时初始化光标不会被捕获到这段代码中,我唯一关心的是如果分配和打开光标则关闭光标。 还假设我正在测试空值等等.. yadda … yadda …(我已经改变了示例以反映这一点,它不是我的问题的焦点所以我没有将它包含在第一版)

如果您在finally中所做的只是关闭光标,那么第二个表单是正确的。 如果openCursor()失败,您将永远不会关闭游标。 甚至都没有设置该变量的值。

正如其他人所暗示的那样,需要注意的是,如果你正在进行额外的初始化,需要自己进行清理,那么逻辑上必须进入finally {}并相应地更改范围。 虽然我认为在这种情况下会进行重组。

底线:正如所写,第一个版本是不必要的复杂。 第二个版本是正确的。

编辑:将我的其他评论纳入后人……

第一个例子似乎无害,因为它所做的就是添加一堆不必要的代码。 (完全不用,如果不清楚的话。)然而,在经典的“更多代码意味着更多潜在的错误”时尚中,有一个隐藏的问题。

如果由于某种原因,“// do something”代码无意中清除了游标变量,那么你将默默地泄漏游标,而在你至少得到NullPointerException之前。 由于额外的代码绝对没有用,所以额外的风险是完全没必要的。

因此,我愿意将第一个例子称为“完全错误”。 我肯定会在代码审查中将其标记出来。

我总是采用第二种方法,因为它允许我将光标设置为final 。 如果您实际上没有尝试从中捕获exception,我没有理由在try子句中看到赋值。

编辑:请注意,从进一步的讨论开始。 这就是我如何处理抛出exception的openCursor调用:

 try { // ALLOCATE RESOURCE final Cursor cursor = db.openCursor(null, null); try { // USE RESOURCE } finally { // DISPOSE RESOURCE cursor.close(); } } catch(OpenCursorException e) { // Handle this appropriately. } 

请注意分配,使用和处置的清晰分离。 唯一有趣的是,如果使用try块抛出了你正在捕获分配try块的相同exception。 ( IOException将是一个特别好的例子,因为打开和读取都可以抛出一个。)在这种情况下,所有内容仍然可以正常清理和处理,但是您可能错误地将失败归因于初始化exception而不是使用exception。 在这种情况下,您将希望捕获内部try块中的exception并立即在那里处理它们。

(更新:问题已经根据这个答案得到纠正,所以这个答案的第一部分不再有意义。)

第一个例子是错误的。 如果db.openCursor失败,它将抛出NullPointerException。 第二个更好。

顺便说一句,我经常看到第一种方法是这样做的:

 Cursor cursor = null; try { cursor = db.openCursor(null, null); // do stuff } finally { if (cursor != null) { cursor.close(); } } 

尽管如此,以第二种方式做到这一点并不是更安全,但它经常在示例中使用,我已经看到它在实际代码中使用了很多。

第二种方法更好的一个原因是// do stuff部分中的代码中的错误可以将Cursor设置为null,从而导致游标不会被关闭并产生泄漏。 总而言之,我认为没有充分的理由使用第一种方法(即使使用空检查进行纠正),以及避免使用它的原因。 坚持第二种方法。

(感谢PSpeed的有用评论!)

不,你终于做对了。

不要分配虚拟值(在这种情况下为null )以禁止编译器有关使用未初始化变量的警告。 相反,请注意警告,并正确初始化变量 – 正如您的第二个“懒惰”示例所示。

这样做真的没有错:

 Cursor cursor = db.openCursor(null, null); try { // do stuff } finally { try { cursor.close(); } catch( SomeOther so ){} } 

如果openCursor()方法没有抛出exception,后者就可以了。 如果确实如此,那么你肯定想要使用前者。 原因是任何exception都会被抛给调用者。 如果调用方法没有设置为处理它,则存在问题。

只要这两个方法参数都不是一个可以抛出自己的exception并需要清理的计算表达式,第二种样式就可以了。

不同的人有不同的意见。但建议使用第一个选项,因为如果打开光标有任何问题,可以抛出和处理exception。这是一种安全的编程方式。