忽略异常
Github和Sourceforge上超过600,000个Java项目中的异常处理概述
Java是使用检查异常的少数几种语言之一。 它们在编译时强制执行,并且需要某种处理。 但是……在实践中会发生什么? 大多数开发人员实际上会处理任何事情吗? 他们怎么做到的?
在这篇文章中,我们将介绍滑铁卢大学最近的一项研究数据,该数据涵盖了来自GitHub和sourceforge的600,000多个Java项目中的异常使用。 让我们深入探讨并回答一些问题。
catch子句中的十大异常类型
嗯,听起来很熟悉? 最近,我们根据生产中1,000多个应用程序中的数据进行了数据紧缩后发布了结果 ,在其中我们检查了抛出的前10种异常类型。
在这种数据紧缩的情况下,研究人员分析了Github和Sourceforge上的Java项目,调查了catch子句并报告了发现的结果。 让我们看看数据集的样子:
好吧,我们在这里有什么? 研究发现,在Java项目中,检查异常占未检查异常数量的几乎三倍。 不能在这里打乱编译器。 在生产数据紧缩中 ,我们看到了相反的结果,其中未检查最高例外。
这里要注意的一个重要区别是,生产紧缩考虑了抛出类型,而本研究指的是捕获类型,它可能与抛出对象不同/更高级别。
另一个见解是,开发人员经常使用Throwable和Exception类在顶级捕获已检查的异常。 情节变浓了 。
为了了解有关如何处理已检查的异常的更多信息,研究人员检查了Exception和Throwable处理程序。 捕获Exception的78%的方法未捕获其任何子类,与Throwable的84%相同。 毫无意义的catch子句。
接下来,让我们找出这些catch子句中发生了什么。 也许有希望。
“大多数程序员会忽略检查的异常,而不会引起注意”
听起来不好吗? 继续阅读。 这是研究的真实,真实,正式内容。 我们中的许多人对被检查的异常有一种刺痛的蜘蛛般的感觉,但是在软件开发中,很少有数据能够为围绕实际代码样式的问题提供冷硬证明。 除了个人经验和定性研究而不是定量研究。
下表显示了在前3个检查的异常捕获块中执行的前几个操作:
我们看到日志语句和e.printStackTrace()在顶部,使它们成为检查异常捕获块中使用的顶部操作,这有助于调试情况并了解发生了什么。
臭名昭著的空渔获量吸引了他们。 Joshua Bloch在“ Effective Java”中描述了理想的情况:“为了捕获故障,异常的详细信息应包含促成异常的所有参数和字段的值”。 空的捕获块正在克服这个目的。
另一个常见用例是引发未检查的异常,该异常将替换已检查的异常。
Mario Fusco在他的Twitter提要上总结得很好:
Java开发人员在受检查的异常捕获块中所做的事情表明,如果您强迫开发人员执行不必要的smtg,则他将使smtg变得愚蠢
— Mario Fusco(@mariofusco) 2016年6月6日
但是等等,还有更多
从检查异常和未检查异常的整体情况来看,这一次仅在Github上,我们看到类似的情况,重新引发获得了更多的欢迎:
总计(6,172,462)个捕获块中有20%为空。 这是很糟糕的。 将点与以下事实联系起来:在层次结构中较高级别的异常比特定类型使用的频率更高,研究人员得出的结论是:“大多数参与者似乎将异常处理作为一项任务给予了较低的优先级,或者将异常包括在他们的任务中。仅在该语言迫使他们处理检查的异常时才进行编码。”
最终,产品质量受损。
重新抛出是怎么回事?
由于在调用堆栈层次结构中引发异常是最流行的catch子句操作,因此研究人员进一步研究了哪种转换最为流行。 下表中汇总了结果:
在#1中,将Exception转换为RuntimeException。 从任何异常类型进行的大多数转换都转换为RuntimeException,从而使未检查的异常变为选中状态。
例外最佳实践
除了数据紧缩及其洞察力之外,本文还提到了约书亚·布洛赫(Joshua Bloch)处理其著名的第二版《有效Java》中的异常的准则(第9章)。 我们认为在此处列出它们也是一个好主意:
1.“仅在例外情况下使用例外”
异常在JVM上造成相当大的开销,将异常用于常规流控制是造成麻烦的原因(是的,即使许多开发人员滥用了它)。 在可执行的例外情况帖子中 ,我们详细介绍了此“常规例外情况”问题。
2.“将检查的异常用于可恢复的条件,将运行时异常用于编程错误”
这意味着,如果开发人员发现检查后的异常不可恢复,则可以将其状态包装在未经检查的异常中,然后将其抛出层次结构以进行日志记录和处理。
3.“避免不必要地使用检查的异常”
仅当通过正确地编码API无法避免异常并且没有替代恢复步骤时,才使用检查的异常。
4.“善用标准例外”
使用已经广泛的Java API中的标准异常可提高可读性。
5.“抛出适合抽象的异常”
在层次结构中前进时,请使用适当的异常类型。
6.“记录每种方法引发的所有异常”
当涉及异常时,没有人会喜欢惊喜。
7.“在详细消息中包含故障捕获信息”
没有有关JVM所处状态的信息,您无法做很多事情来确保不再发生该异常。 并不是每个人都有Takipi掩盖他们的背部。
8.“不要忽略异常”
所有异常都应导致某种行为,您还需要它们做什么?
要了解有关这些准则的更多信息,请查看上一篇有关可操作异常的博客文章 ,以及最近一次涵盖1000多个生产应用程序的生产数据紧缩的教训,以了解其日志中的内容以及遇到的十大异常 。
我们到底在看什么呢?
这项研究的数据来自加拿大安大略省滑铁卢大学的David R. Cheriton计算机科学学院的Suman Nakshatri , Maithri Hegde和Sahithi Thandra的研究论文 。
研究人员研究了780万个Github项目和70万个Sourceforge项目的数据库 ,提取了Java项目,并检查了BOA领域特定语言对catch块在采矿软件存储库中的使用情况。
最后的想法
例外情况应保留给例外情况,但是……其他情况在实践中会发生。 被检查的异常变得不受检查,到处都是空的catch块,控制流与错误流混合在一起,有很多噪音,关键数据丢失了。 一团糟。
这是我们构建Takipi的主要动机, Takipi是一个Java代理,用于监视生产中的JVM,并负责使用您需要了解异常行为(以及如何避免异常)的所有信息来填补空白。
翻译自: https://www.javacodegeeks.com/2016/06/ignore-checked-exceptions-cool-devs-based-600000-java-projects.html
忽略异常