在java中使用每个方法的大尝试catch是一个已知的好习惯吗?
我最近接受了采访,面试官要我做技术testing,看看我的知识。 完成之后,他向我反馈了我是如何做到这一点的,我没有想到,也很感激,因为很less有面试官如果不想聘用你。
他告诉我,他看到我的代码不好的一件事是,我在每个写的方法中使用了不止一个try-catch块。 因为我觉得这很有趣,所以这引起我的注意。
我相信目前我应该做一个try-catch块,在那里有一个语义上可区分的代码块,它有一个或多个方法可以抛出需要被捕获的exception。 我遵循的唯一例外是,如果两个方法抛出相同的exceptiontypes,我最好把它们放在不同的try-catch块中,以清楚地区分何时抛出exception和抛出exception的原因。
这与面试官要求我做的事情有很大的不同。 那么每个方法只使用一个try-catch块是一个已知的好习惯? 如果这是一个已知的良好做法,那么做什么好处?
编辑:我非常感谢你的想法,这是非常好的。 虽然注意到我在问这是否是已知的好习惯。 这是,如果大多数程序员会同意这一点,或者这在某些书中被写成一个好的实践
对我来说,两个try-catch块使大多数方法太长。 如果这个方法做了很多事情,它会混淆这个意图。
有两个try-catch块,至less要做四件事,准确的说
- 主stream两种情况(两次尝试)
- 两种情况下的error handling(catch块)
我宁愿在每个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 ); }
罗伯特·C·马丁(Robert C. Martin)在“清洁法典”中将其提升到了一个新的水平,
如果关键字'try'存在于函数中,它应该是函数中的第一个单词,并且catch / finally块之后应该没有任何内容。
我肯定会用两个单独的try / catch块重构方法到更小的方法。
我会说,如果你发现自己用try/catch
封装了两个独立的代码块,你应该考虑将这些块重构成单独的方法。 如果这是你面试时使用的模式,那么你可能误解了你的面试官。
如果algorithm需要,使用两个try/catch
块是完全正确的。 我经常在catch块中使用一个新的try/catch
来确保安全的清理,所以一个blanket语句是不可能的。
为了回答你的问题,当我们谈论现代JVM时,实际上在代码中应用了很多优化,当你编写一些效率低下的代码时,JVM会自动引入优化。
请参考( Java:进入/使用“try-catch”块的开销)中的答案。
所以好的做法并不重要。
个人而言,我相信不能将任何东西封装在try-catch
, static
, synchronized
等块中。
让我们让我们的代码更易读的人谁将在这个工作。 如果发现exception,最好明确地指出哪一段代码正在抛出它。
没有读者的猜测,这就是为什么JVMs是聪明的,写你想要的,使人类更好,JVM照顾的优化部分。
编辑:我读了很多书,我没有find任何地方说,一个大的尝试抓住比多个小的更好。
而且,开发者社区中的许多人则相反。
我尽量避免重复在catch块。 如果一个方法中的所有exception都在catch块中接受相同的处理,那么继续将它们一起捕获。 如果你需要与他们做不同的事情,那么分别抓住他们。
例如,在这里我们可以把所有exception一起捕获,因为任何一种exception都意味着整个方法失败:
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); }
(这段代码的存在纯粹是为了说明捕捉exception的这一点,我恳求你不要理会这个事实在其他方面是非常可怕的)
至于我,只有一个try-catch
块在方法中包含了所有的“危险”代码。 关于当两行抛出同样的exception时应该责怪谁,你总是有堆栈跟踪。
另外,在一个方法中有多个try-catch
通常意味着有多个return
行(这也可能使代码难以执行),因为如果在第一次try-catch
时出错,继续运行代码的其余部分是没有意义的。
在这里你可以find一些“标准”的最佳实践,以防万一你会发现它们有用。
http://howtodoinjava.com/2013/04/04/java-exception-handling-best-practices/
考虑代码的上下文也很重要。 如果你正在写繁重的IO代码,那么你可能需要知道哪些代码部分失败。 我没有看到任何地方的尝试…赶上是为了给你一个机会,从一个问题中恢复。
所以如果从一个文件中读取IOexception,您可能需要重试读取。 与写作一样。 但如果你有一个大的尝试…赶上你不知道要重试。
这是经常启动Java-flamewar的另一件事… 😉
基本上,performance事项只是抛出exception。 所以使用less量的try-catch
块应该不会影响性能。 在某些人看来,编写这样的代码来混淆代码,甚至不记得“干净的代码”,在另一些人看来,最好是只try
用于实际上可以抛出任何exception的代码行。
这取决于你决定(或团队大会)。