Java异常处理 - 样式

Joe*_*oel 10 java exception-handling

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

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

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

        Cursor cursor = db.openCursor(null, null);
        try {           
            // do stuff
        } finally {
            cursor.close();
        }
Run Code Online (Sandbox Code Playgroud)

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

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

编辑 -假设我很高兴,同时初始化光标不是在这个代码块被抓,我在这个例子中唯一关心的是关闭游标,如果它通过openCursor抛出的异常分配和打开.还假设我正在测试空值等等.. yadda ... yadda ...(我已经改变了示例来反映这一点,它不是我的问题的焦点,所以我没有将它包含在第一版)

jdm*_*hal 13

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

编辑:请注意,从进一步的讨论开始.这就是我如何处理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.
}
Run Code Online (Sandbox Code Playgroud)

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


Mar*_*ers 11

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

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

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

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

尽管如此,这样做并不是更安全,但它经常用于示例中,并且我已经看到它在实际代码中使用了很多.

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

(感谢PSpeed的有用评论!)

  • 例如,如果某些东西搞砸了// do stuff会使游标变量无效,那么你现在正在默默地将游标泄漏到之前你已经获得NPE的位置.不必要的风险. (4认同)

eri*_*son 6

不,你终于做对了.

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


PSp*_*eed 6

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

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

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

编辑:结合我的其他评论为后代...

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

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

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