【问题标题】:(Java) Try-catching specific lines of code vs Try-catching the whole function(Java) 尝试捕获特定的代码行与尝试捕获整个函数
【发布时间】:2016-02-14 22:13:49
【问题描述】:

所以我正在用 Java 做一个小项目,我已经归结为 main 方法,但我不确定我应该如何正确处理 try-catch 异常。

我应该是:

尝试捕获我知道可能会引发异常的特定代码行? 喜欢:

public class Stuff {
    public static void main(String[] args) {
        try {
            // code that will probably throw exception 1 or 2
        } catch (exception1 e) {
            // handle exception 1
        } catch (exception2 e) {
            // handle exception 2
        }

        //rest of code that probably won't throw any exceptions
    }
}

尝试捕获整个main方法即使try块中的某些代码不会抛出异常?喜欢:

public class Stuff {
    public static void main(String[] args) {
        try {
            // code that will probably throw exception 1 or 2
            // rest of code that probably won't throw any exceptions
        } catch (exception1 e) {
            // handle exception 1
        } catch (exception2 e) {
            // handle exception 2
        }
    }
}

【问题讨论】:

  • 哪个更易读,对你更好。
  • @rdean400,这是有道理的。我想知道是否有任何约定或某种更可取的约定(不是从优化的角度来看),但我想在阅读 Maxim Golman 的链接后确实没有区别。谢谢!
  • 理想情况下,我们应该有更小的 try 块,并且有非常接近异常源的特定异常处理逻辑。但是,这可能太冗长了,而且我们往往很懒惰;因此,如果我们可以摆脱较粗的块,我们会的。

标签: java exception exception-handling try-catch


【解决方案1】:

需要考虑的一点是,如果抛出异常,在 catch 块之后运行的代码是否仍然有效。例如,考虑以下方法:

private void readFile()
{
    List<String> lines = null;
    try
    {
        lines = Files.readAllLines(Paths.get("/to/my/file.txt"));
    }
    catch (IOException e)
    {
        // log exception...
    }

    for (String line : lines)
    {
        System.out.println(line);
    }
}

如果readAllLines 抛出IOException,那么catch 块之后的代码将抛出NullPointerException


还有一个更大的问题是决定何时捕获和重新抛出异常。我通过问自己这个问题来回答它:

“如果抛出此异常,我的方法能否履行其约定?”

YES:处理异常并继续履行方法的约定。
NO:重新抛出异常(在throws 子句中或换行更合适的异常类型)。

例如,this method

public static List<String> readAllLines(Path path) throws IOException

如果文件不存在,则无法返回文件行的列表,因此会抛出IOException

另一方面,this method

public static boolean deleteIfExists(Path path) throws IOException

如果文件不存在,则不会抛出异常(它会返回boolean 来告诉您发生了什么)。这种方法的契约的一种思考方式是,“在这个方法执行之后,path 处不会有文件”。所以在这种情况下,如果文件不存在,合同仍然履行。

【讨论】:

  • 这很有意义,询问在 catch 之后运行的代码是否依赖于 try 块中的代码有助于我正确看待它。就我而言,代码依赖于 try 块的代码,所以我认为将整个 main 方法包含在 try 块中将是最有益的,因为它会在捕获异常后停止运行。谢谢!
【解决方案2】:

这取决于 - 如果引发任何异常,是否应该执行非异常代码?这不是“最佳实践”问题,而是“您的规格是什么?”问题。

假设您的代码如下所示:

String someValue;
try {
    someValue = parseSomething();
} catch (ParseFailureException e) {
    someValue = defaultValue;
}
// Continue, possibly using the default value

在这种情况下,您应该只换行。另一方面,也许您的代码如下所示:

String someValue;
try {
    someValue = parseSomething();
} catch (ParseFailureException e) {
    log.fatal("The universe is crashing! Run for your lives!");
    System.exit();
}
// Continue, assuming that parsing succeeded

在这种情况下,这是一种风格选择。这两种方法都是有效的,尽管在这个例子中出现了如此极端的失败,最好简单地声明该方法抛出一些东西并完全忘记 try/catch。事实上,无论你的处理代码是什么,如果你的方法在它之后唯一要做的事情就是退出,你应该考虑省略 try/catch 并改用 throws 子句。

然而,这第三种情况在客观上是错误的:

String someValue;
try {
    someValue = parseSomething();
} catch (ParseFailureException e) {
    log.info("something strange happened");
    // Don't bother the calling code with the exception, it can't handle it.
}
// Continue, assuming that parsing succeeded

在这种情况下,继续代码必须放在try 块内。

【讨论】:

  • @kuporific 提到了与您在 catch 之后的代码是否依赖于 try 块中的代码方面所做的相同的事情。也感谢您的建议!它确实有助于正确看待解决方案。另外,只是一个小题外的问题(实际上并不是)在 try-block 中抛出异常并捕获它会更好,还是只是 System.exit(0)?假设在这两种情况下,您只想输出一条消息并退出程序。
猜你喜欢
  • 2017-09-12
  • 1970-01-01
  • 2013-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-28
  • 2021-12-13
  • 1970-01-01
相关资源
最近更新 更多