1. 程式人生 > >Checked exceptions: Java’s biggest mistake-檢查型異常:Java最大的錯誤(翻譯)

Checked exceptions: Java’s biggest mistake-檢查型異常:Java最大的錯誤(翻譯)

lsb ++ 好的 stream abstract throw features inter 不用

原文地址: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.

正如Stephen Colebourn所說,假如你的項目仍然在使用或提倡檢查型異常,你已經落後5-10年了,Java已經不使用了。

Checked exceptions: Java’s biggest mistake-檢查型異常:Java最大的錯誤(翻譯)