在java中对每个方法使用一个大的try-catch是一种已知的好习惯吗? [关闭]

Posted

技术标签:

【中文标题】在java中对每个方法使用一个大的try-catch是一种已知的好习惯吗? [关闭]【英文标题】:Is it a known good practice to use a big try-catch per method in java? [closed] 【发布时间】:2013-09-18 00:53:28 【问题描述】:

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

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

我认为目前我应该制作 try-catch 块,其中存在语义上可区分的代码块,该代码块具有一个或多个可以引发需要捕获的异常的方法。我遵循的唯一例外是,如果两个方法抛出相同的异常类型,我最好将它们放在不同的 try-catch 块中,以便在调试时清楚地区分抛出异常的位置和原因。

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

编辑:非常感谢您对此的想法,这非常好。尽管请注意,我在问这是否是一种已知的良好做法。这是,如果大多数程序员都同意这一点,或者这是在某些书中作为一种好的做法写的

【问题讨论】:

我同意你的观点。面试官并不总是正确的。 @tbsalling 不要误会我的意思。我不是说面试官错了。这可能是我错过了一些我不知道的东西。 我的看法是你应该在行为不同的地方使用不同的 try/catch 块。如果两个块中的捕获内容相同,我将只使用一个。这当然会引出一个问题,如果有多个 try/catch 块,因为代码与 catch 功能不同,是否应该将其分解为多个方法。 方法中有许多try 语句的问题可能是您的方法太长或者您过于依赖异常。如果不是这样的话,我认为他的意见是不合理的。 也许面试官想看看你对代码审查环境中的批评有何反应? 【参考方案1】:

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

准确地说,有了两个 try-catch 块,它至少做了四件事

主流的两种情况(两个 try 块) 错误处理的两种情况 (捕获块)

我宁愿从每个 try-catch 块中制作简短而清晰的方法

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);

“清洁代码”中的 Robert C. Martin 将其提升到一个新的水平,建议:

如果函数中存在关键字“try”,则它应该是函数中的第一个单词,并且在 catch/finally 块之后应该没有任何内容。

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

【讨论】:

我更喜欢你的回答,因为你已经找到了我想要找到的东西;即一个好的和著名的参考,建议或鼓励每个方法/函数只写一个 try-catch,并说明这样做的原因。看来我终于可以从我的面试官那里学到一些东西了。【参考方案2】:

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

如果算法需要,使用两个try/catch 块是完全可以的。我经常在 catch 块中使用新的 try/catch 以确保安全清理,因此不可能使用一揽子声明。

【讨论】:

+1 同意。一种方法应该只用于一个目的。 此外,如果您将两个单独的代码块包装在同一个 try/catch 中,那么您无法在 catch 块中实现一种正确的恢复算法,而不必区分这两种情况,使用 "if ",哪种方式违背了捕获的目的,使其变得比必要的复杂。 这是最好的答案,因为它可以识别实际问题。 完美,讲讲实际原因,方法的Single Responsibility。【参考方案3】:

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

请参考 (Java: overhead of entering/using "try-catch" blocks?) 中的答案。

所以好的做法并不重要。

就个人而言,我认为不得在try-catchstaticsynchronized 等块中不必要地封装任何内容。

让我们让我们的代码对从事此工作的人更具可读性。如果捕获到异常,最好明确指出是哪段代码抛出了它。

读者无需猜测,这就是为什么 JVM 很聪明,可以随心所欲地编写,让它对人类更好,而 JVM 负责优化部分。

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

此外,开发者社区中的许多人认为相反。

【讨论】:

谢谢@dharam,这就是我一直在寻找的答案。我们每个人都有理由思考一种或另一种方式来操作这个 try-catch 块以获得更好的干净代码或性能。虽然如果人们同意你的话;即不知道好的做法,然后我发现这不是使用个人偏好来判断求职者的好方法。我希望根据它普遍接受的内容来判断,然后被告知按照团队对代码风格的偏好进行编码。我希望能从面试官那里学到一些东西,但我似乎不会。 ://【参考方案4】:

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

例如,这里我们可以一起捕获所有异常,因为任何一种异常都意味着整个方法都失败了:

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;
    

而在这里,我们对每组调用都有不同的回退行为,因此我们分别捕获:

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);

(此代码的存在纯粹是为了说明关于捕获异常的这一点;我请求你忽略它在其他方面非常可怕的事实)

【讨论】:

【参考方案5】:

就我而言,只有一个 try-catch 块将所有“危险”代码包装在一个方法中会更清楚。关于当两行抛出相同的异常时该怪谁,您将始终拥有堆栈跟踪。

此外,在一个方法中包含多个 try-catch 通常意味着包含多个 return 行(这也可能使代码执行难以跟踪),因为如果出现问题,很有可能首先try-catch,继续运行其余代码没有意义。

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

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

【讨论】:

【参考方案6】:

这是另一个经常引发 Java-flamewar 的事情...... ;-)

基本上,性能问题只抛出异常。因此,使用少量 try-catch 块根本不会影响性能。 在某些人看来,以这种方式编写代码会混淆代码,甚至不记得“干净的代码”,而在其他人看来,最好仅将try 用于实际上可能引发任何异常的行。

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

【讨论】:

【参考方案7】:

考虑代码的上下文也很重要。如果您正在编写具有大量 IO 的代码,那么您可能需要知道代码的哪些部分失败了。我还没有在任何地方看到 try...catch 旨在让您有机会从问题中恢复过来。

因此,如果您在读取一个文件时遇到 IO 异常,您可能需要重试读取。写作也一样。但是,如果您进行了一次大尝试...catch,您将不知道该重试哪个。

【讨论】:

以上是关于在java中对每个方法使用一个大的try-catch是一种已知的好习惯吗? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Snowflake 中对非常大的表进行删除操作的最佳方法是啥?

excel中对数据进行分类求和

如何在 PySpark 中的大型 Spark 数据框中对行的每个子集进行映射操作

Java中对JSONArray中的对象的某个字段进行排序

Java中对JSONArray中的对象的某个字段进行排序

如何在java中对不同的数据类型进行排序并将它们打印在一个表中? (使用方法重载)