原文地址:http://literatejava.com/exceptions/checked-exceptions-javas-biggest-mistake/
仅供参考,毕竟我四级都没过
Checked exceptions have always been a controversial feature of the Java language.
检查型异常一直是Java语言当中有争议的特性
Advocates claim they ensure checking & recovery from failures. Detractors say “catch” blocks can almost never recover from an exception, and are a frequent source of mistakes.
支持者表示对于异常总是能检查到并恢复。而反对者则说catch到的那些代码块几乎不能从Exception中恢复,并且常常产生其他错误。
Meanwhile, Java 8 and lambdas are here. Are checked exceptions becoming obsolete in the Java world?
现在,Java8和lambdas来了。那么检查型异常是否已经变的过时了?
The Intent of Checked Exceptions
In the mid 90’s, James Gosling at Sun came up with a new language.
在90年代中期,Sun公司的James Gosling提出了一种新的语言
At the time, C++ programming required every single function return to be checked for error. He decided there had to be a better way, and built the concept of “exceptions” into Java.
当时,C++程序要求检查每个方法的返回错误。James觉得应该会有更好的方式,然后就将“异常”的观念带到了Java当中
The intent of checked exceptions was to locally flag, and force developers to handle, possible exceptions. Checked exceptions have to be declared on a method signature, or handled.
检查型异常的目的是在本地做标记,然后强迫程序员去处理可能发生的异常,你必须选择在方法定义上声明这个异常或者直接处理
This was intended to encourage software reliability & resilience. There was an intent to “recover” from contingencies – predictable outcomes other than success, such as InsufficientFundsException on attempting a payment. There was less clarity, as to what “recovery” actually entailed.
这是为了加强软件的可靠性和弹性。它希望可以从意外当中“恢复”到除了成功之外的某种可预见的结果,比如在支付中抛出InsufficientFundsException 异常。但是“恢复”真正带来了什么,却一点都不明确。
Runtime exceptions were also included in Java. Since null pointers, data errors, and illegal states/ accesses could occur anywhere in code, these were made subtypes of RuntimeException.
运行期异常也被包括在了Java当中,包括空指针,数据错误和非法的访问等都可能发生在程序的任何地方。
Runtime exceptions can be thrown anywhere, without requiring to be declared, and are much more convenient. But would it be correct to use them instead?
不需要先声明就可以在任意地方抛出运行期异常,非常方便。但是这样是不是真的是对的?
The Drawbacks
The crucial point here, is that runtime & checked exceptions are functionally equivalent. There is no handling or recovery which checked exceptions can do, that runtime exceptions can’t.
关键点在于,运行时异常和检查型异常在功能上是相似的。不会有检查型异常可以处理和恢复但是运行期异常不能的情况。
The biggest argument against “checked” exceptions is that most exceptions can’t be fixed. The simple fact is, we don’t own the code/ subsystem that broke. We can’t see the implementation, we’re not responsible for it, and can’t fix it.
检查型异常最大的争论点在于大多数异常并不能被修复。事实上,我们拿不到有问题的代码或者子系统。我们看不到实现,我们不能处理它们,也无法修复它们。
Particularly problematic were the areas of JDBC (SQLException) and RMI for EJB (RemoteException). Rather than identifying fixable contingencies as per the original “checked exception” concept, these forced pervasive systemic reliability issues, not actually fixable, to be widely declared.
特别有问题的是JDBC的SQLException和EJB当中RMI部分的RemoteException异常。这些被强迫关注,普遍存在的系统问题(事实上是不能修复的),被到处声明,而不是按照最初“检查型异常”的想法去识别可以修复的异常。
For any method, the possibility of failure includes all sub-methods called by it. Potential failures accumulate up the call tree. Declaring these on method signatures no longer offers a specific & local highlight for the developer to watch for – declared exceptions spread throughout the call tree.
对于任何方法,错误可能发生在它调用的任何一个子方法。这些错误都堆积在访问树上。可是在方法声明上不会特意标识这些异常。
Most EJB developers have experienced this – declared exceptions become required on methods through the tier, or entire codebase. Calling a method with different exceptions requires dozens of methods to be adjusted.
大多数EJB开发者都有这样的经历-通过层级或是代码库调用方法必须声明异常。调用一个会产生不同异常的方法可能需要调整更多的方法。
Many developers were told to catch low-level exceptions, and rethrow them again as higher (application-level) checked exceptions. This required vast numbers – 2000 per project, upwards – of non-functional “catch-throw” blocks.
很多开发者会被要求捕获低级的异常,然后作为更高级的检查型异常再次抛出。这会造成一个项目中,可能产生2000个没什么用的“catch-throw”代码块。
Swallowing exceptions, concealing the cause, double logging, and returning ‘null’/ uninitialized data all became common. Most projects could count 600+ mis-coded or outright errors.
Swallowing exceptions,concealing the cause,double logging以及返回null或者未初始化数据都是很常见的错误。大多数项目可能有多达600多个错误代码。
Eventually, developers rebelled against the vast numbers of “catch” blocks, and the source of error these had become.
所以,开发人员反对大量的“catch”代码块,并且这些代码块已经成为错误的来源。
Checked Exceptions – incompatible with Functional Coding
And then we get to Java 8, with its new functional programming features – such as lambdas, Streams, and function composition.
现在,我们有了Java8,它带来了新的特性-有lambdas表达式,streams和函数式编程。
These features are built on generics – parameter & return types are genericized, so that iteration & stream operations ( forEach
, map
, flatMap
) can be written which perform a common operation, regardless of item type.
这些特性建立在泛型上-参数和返回值类型是通用的,所以编写的iteration和stream(forEach,mapflatMap)可以执行常见操作,而不用管它的类型。
Unlike data types, however, declared exceptions can’t be genericized.
但是与数据类型不同,声明式异常不能被通用化。
There is no possibility in Java to provide a stream operation (like, for example, Stream.map
) which takes a lambda declaring some checked exception, & transparently passes that same checked exception to surrounding code.
Java不可能提供一个Stream操作(比如Stream.map),用一个lambda表达式声明检查型异常,然后显式的将同样的检查型异常传递给其他代码。
This has always been a major points against checked exceptions – all intervening code, between a throw and the receiving “catch” block, is forced to be aware of exceptions.
这是反对检查型异常主要的点-所有位于throw和catch块的代码,都*要注意可能发生的异常。
The workaround, of “wrapping” it in a RuntimeException, conceals the original type of the exception – rendering the exception-specific “catch” blocks envisaged in the original concept useless.
在RuntimeException中,封装了它的方法,隐藏了异常的原始类型-使原始概念中异常的catch块变的无用。
Finally we can capture Java’s new philosophy in a nutshell, by noting that none of the new “functional interfaces” in Java 8 declare checked exceptions.
我们了解了Java新的理念,Java8中没有新的“功能接口”声明了检查型异常。
Conclusion
Exceptions in Java provided major benefits in reliability & error-handling over earlier languages. Java enabled reliable server & business software, in a way C/ C++ never could.
Java的异常比早起的语言更可靠,更强的错误处理能力。
Checked exceptions were, in their original form, an attempt to handle contingencies rather than failures. The laudable goal was to highlight specific predictable points (unable to connect, file not found, etc) & ensure developers handled these.
检查型异常,尝试去处理意外情况而非错误。优点是明确可预见的部分(连接不上,文件找不到等等),并确保开发者处理这些问题。
What was never included in the original concept, was to force a vast range of systemic & unrecoverable failures to be declared. These failures were never correct to be declared as checked exceptions.
最初的设想中并不包括声明大量系统性的和不能恢复的错误。这些错误不会被声明为检查型异常。
Failures are generally possible in code, and EJB, web & Swing/AWT containers already cater for this by providing an outermost “failed request” exception-handler. The most basic correct strategy is to rollback the transaction & return an error.
但代码通常会发生错误,EJB、Web和 Swing/AWT容器通过提供最外层的“失败请求”异常来处理发生的问题。最基本的策略是回滚事务然后返回一个错误。
Runtime exceptions allow any exception-handling possible with checked exceptions, but avoid restrictive coding restraints. This simplifies coding & makes it easier to follow best practice of throw early, catch late where exceptions are handled at the outermost/ highest possible level.
运行时异常允许使用检查型异常进行任何的异常处理,但要避免编码限制。这简化编码方式,更容易遵循throw early, catch late,也更方便在最外层或*别处理异常。
Leading Java frameworks and influences have now definitively moved away from checked exceptions. Spring, Hibernate and modern Java frameworks/ vendors use only runtime exceptions, and this convenience is a major factor in their popularity.
领先的java框架已经决定移除检查型异常。Spring、Hibernate 和现代的Java框架或供应商只使用运行期异常,便利性是主要原因。
Personalities such Josh Bloch (Java Collections framework), Rod Johnson, Anders Hejlsberg (father of C#), Gavin King and Stephen Colebourn (JodaTime) have all come out against checked exceptions.
Josh Bloch (Java集合框架),Rod Johnson,Anders Hejlsberg (C#之父),Gavin King and Stephen Colebourn (JodaTime)都反对检查型异常。
Now, in Java 8, lambdas are the fundamental step forward. These language features abstract the “flow of control” from functional operations within. As we’ve seen, this makes checked exceptions & the requirement to “declare or handle immediately” obsolete.
在Java8中,lambdas是一个进步,这些语言特征从基本操作中抽象出控制流,这使得检查型异常和“声明或者立即处理”的观念被废弃。
For developers, it is always important to pay attention to reliability & diagnose likely points of failure (contingencies) such as file open, database connection, etc. If we provide good error messages at this points, we will have created self-diagnosing software – a pinnacle of engineering achievement.
对于开发者而言,关注可能发生的故障比如文件打开,数据库连接等等是非常重要的。如果我们能提供适宜的错误信息,我们将创造自我诊断软件,这将是人生巅峰。
But we should do this with unchecked exceptions, and if we have to rethrow, should always use RuntimeException or an app-specific subclass.
但是我们需要使用到检查型异常,假如我们不得不重新抛出,应该使用运行期异常或是特定的应用程序级子类。
As Stephen Colebourn says, if your projects are still using or advocating checked exceptions, your skills are 5-10 years out date. Java has moved on.