关于异常处理:在java中使用大的try-catch per方法是一种众所周知的好习惯吗?

Is it a known good practice to use a big try-catch per method in java?

我最近接受了面试,面试官想让我做一次技术测试来了解我的知识。在我完成后,他给了我关于我是如何做到的反馈,这是我没有预料到的,我很感激,因为很少有面试官会这样做,如果他们不想雇用你。

他告诉我他认为我的代码不好的地方之一是我在我编写的每个方法中使用了不止一个try-catch块。这引起了我的注意,因为我觉得它很有趣。

我相信现在我应该让Try-Catch块出现在语义上可区分的代码块中,其中有一个或多个方法可以抛出需要捕获的异常。我遵循的唯一例外是,如果两个方法抛出相同的异常类型,我最好将它们放在不同的Try-Catch块中,以便在调试异常的位置和原因时清楚地区分。

这与面试官想要我做的有很大的不同。那么,每个方法只使用一个try-catch块是一个已知的良好实践吗?如果这是一种已知的良好做法,那么这样做的好处是什么?

编辑:非常感谢你对这个问题的看法,这很好。尽管请注意,我在问这是否是一个已知的良好做法。这是,如果大多数程序员都同意这一点,或者这是一个很好的实践


对我来说,两个try-catch块会使大多数方法太长。如果方法做了很多事情,它会混淆意图。

用两个试抓块,它至少能做四件事,准确地说

  • 两个主流案例(两个试块)
  • 错误处理两例(捕捉块)

我宁愿在每一个try-catch块中做出简短清晰的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
private getHostNameFromConfigFile(String configFile, String defaultHostName) {
    try {
        BufferedReader reader = new BufferedReader(new FileReader(configFile));
        return reader.readLine();
    } catch (IOException e) {
        return defaultHostName;
    }
}
public Collection<String> readServerHostnames(File mainServerConfigFile, File  backupServerConfigFile) {
    String mainServerHostname=getHostNameFromConfigFile(mainServerConfigFile,"default- server.example.org");
    String backupServerHostName=getHostNameFromConfigFile(backupServerConfigFile,"default- server.example.ru")
    return Arrays.asList(mainServerHostname,backupServerHostName );
}

罗伯特·C·马丁在《清洁代码》一书中提到了下一个层次,他建议:

if the keyword 'try' exists in a function, it should be the very first word in the function and that there should be nothing after the catch/finally blocks.

我肯定会用两个单独的try/catch块将该方法重构为较小的方法。


我想说,如果您发现自己用try/catch包装了两个单独的代码块,那么应该考虑将这些代码块重构为单独的方法。如果这是你在面试中使用的一种模式,也许你误解了面试官。

如果算法需要,最好使用两个try/catch块。我经常在catch块中使用一个新的try/catch,以确保安全清理,因此不可能使用一个笼统的语句。


为了回答您的问题,当我们讨论现代的JVM,它实际上在代码中应用了很多优化,当您编写一些效率低下的代码时,JVM将自动引入优化。

请参考答案(Java:输入/使用的开销)"尝试捕捉"块?.

所以良好的实践并不重要。

我个人认为,不一定要用try-catchstaticsynchronized等块封装任何东西。

让我们的代码对那些将要进行此项工作的人更具可读性。如果捕获到异常,最好显式地突出显示哪段代码正在抛出它。

读者不必猜测,这就是为什么JVM是聪明的,你想写就写,让它对人类更好,而JVM负责优化部分。

编辑:我读了很多书,但没有找到一个地方说一个大的尝试捕捉比多个小的好。

此外,开发人员社区中的许多人都持相反的观点。


我尽量避免在catch块中重复。如果一个方法中的所有异常在catch块中都得到相同的处理,那么继续执行并将它们全部捕获。如果你需要对它们做不同的事情,那么就分别抓住它们。

例如,这里我们可以将所有异常集中在一起,因为任何类型的异常都意味着整个方法失败:

1
2
3
4
5
6
7
8
9
10
public PasswordAuthentication readAuthenticationDetails(File authenticationFile) {
    try {
        BufferedReader reader = new BufferedReader(new FileReader(authenticationFile));
        String username = reader.readLine();
        String password = reader.readLine();
        return new PasswordAuthentication(username, password.toCharArray());
    } catch (IOException e) {
        return null;
    }
}

然而,对于每组调用,我们有不同的回退行为,因此我们分别捕捉:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public Collection<String> readServerHostnames(File mainServerConfigFile, File backupServerConfigFile) {
    String mainServerHostname;
    try {
        BufferedReader reader = new BufferedReader(new FileReader(mainServerConfigFile));
        mainServerHostname = reader.readLine();
    } catch (IOException e) {
        mainServerHostname ="default-server.example.org";
    }

    String backupServerHostname;
    try {
        BufferedReader reader = new BufferedReader(new FileReader(backupServerConfigFile));
        backupServerHostname = reader.readLine();
    } catch (IOException e) {
        backupServerHostname ="default-server.example.ru";
    }

    return Arrays.asList(mainServerHostname, backupServerHostname);
}

(此代码的存在纯粹是为了说明有关捕获异常的这一点;请您忽略这一事实,即在其他方面它是完全可怕的)


对于我来说,只需要一个try-catch块就可以用一个方法包装所有"危险"代码。关于当两行抛出同一个异常时该责备谁,您将始终拥有stacktrace。

此外,在一个方法中有多个try-catch通常意味着有多个return行(这也很难一眼就跟踪代码执行),因为如果在第一个try-catch中出现问题,那么继续运行其余的代码是没有意义的。

在这里,您可以找到一些"标准"的最佳实践,以防您发现它们有用。-

http://howtoonijava.com/2013/04/04/java-exception-handling-best-practices/


考虑代码的上下文也很重要。如果您使用大量IO编写代码,那么您可能需要知道代码的哪些部分出现故障。我什么地方也没看到尝试的要点……接球是为了给你一个从问题中恢复的机会。

因此,如果从一个文件中读取时出现IO异常,则可能需要重试读取。写作也是如此。但是如果你尝试了一次……接住,你就不知道该再试哪一次了。


这是另一个经常启动Java FLAMEAR…;-)

基本上,对于性能来说,只需要抛出异常。因此,使用少量的try-catch块根本不应该影响性能。在一些人看来,用这种方式编写代码会使代码变得模糊,甚至不会回忆起"干净的代码",在另一些人看来,最好只对实际可以抛出任何异常的行使用try

由你决定(或团队会议)。