Checked exception trong Java

Tiếp chuyện hôm trước, nhưng hôm nay không có C#.

Không quan tâm tới chuyện checked exception trong Java hay dở thế nào nữa, tại vì chúng ta không phải là Sun. Họ làm sao là quyền của họ. Việc của chúng ta là làm theo ý họ theo cách tốt nhất có thể.

Sun có một bài dài về checked exception, và họ kết luận:

Generally speaking, do not throw a RuntimeException or create a subclass of RuntimeException simply because you don’t want to be bothered with specifying the exceptions your methods can throw.

Here’s the bottom line guideline: If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.

Tức là với Sun, lập trình viên phải ưu tiên xem xét checked exception trước. Trong quyển Effective Java: Programming Language Guide, Josh Bloch (một trong những người tham gia thiết kế Java) cụ thể hóa các chỉ dẫn trên một chút:

  • Item 39: Use exceptions only for exceptional conditions. That is, do not use exceptions for control flow, such as catching NoSuchElementException  when calling instead of first checking Iterator.hasNext().
  • Item 40: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors. Here, Bloch echoes the conventional Sun wisdom — that runtime exceptions should be used only to indicate programming errors, such as precondition violations.
  • Item 41: Avoid unnecessary use of checked exceptions. In other words, don’t use checked exceptions for conditions from which the caller could not possibly recover, or for which the only foreseeable response would be for the program to exit.
  • Item 43: Throw exceptions appropriate to the abstraction. In other words, exceptions thrown by a method should be defined at an abstraction level consistent with what the method does, not necessarily with the low-level details of how it is implemented. For example, a method that loads resources from files, databases, or JNDI should throw some sort of ResourceNotFound exception when it cannot find a resource (generally using exception chaining to preserve the underlying cause), rather than the lower-level IOException, SQLException, or NamingException.

Tuy nhiên, như đã nói, các ông trùm đều cho rằng checked exception theo kiểu Java phá vỡ tính bao đóng, làm code dài, khó bảo trì, v.v cho nên một hướng dẫn chung chung thế kia có lẽ là chưa đủ. Có hai lựa chọn có vẻ đáng chú ý.

Thứ nhất là quan điểm “cực đoan” của Bruce Eckel (người viết mấy quyển Thinking in), chỉ nên có checked exception. Bruce Eckel đề xuất việc mở rộng RuntimeException thành ExceptionAdapter có tác dụng:

Here, you’re still able to catch the specific type of exception but you’re not forced to put in all the exception specifications and try-catch clauses everywhere between the origin of the exception and the place that it’s caught. An even more importantly, no one writing code is tempted to swallow the exception and thus erase it. If you forget to catch some exception, it will show up at the top level. If you want to catch exceptions somewhere in between, you can.

Thứ hai là quan điểm “ôn hòa” của Rod Johnson trong J2EE Design and Development. Giống như Anders Hejlsberg, ông này cũng cho là checked exception là cần thiết, vấn đề là dùng sao cho hợp lí (trong điều kiện vẫn chưa tìm ra giải pháp nào phù hợp về mặt ngôn ngữ):

Checked exceptions are much superior to error return codes (as used in many older languages). Sooner or later (probably sooner) someone will fail to check an error return value; it’s good to use the compiler to enforce correct error handling. Such checked exceptions are as integral to an object’s API as parameters and return values.

However, I don’t recommend using checked exceptions unless callers are likely to be able to handle them. In particular, checked exceptions shouldn’t be used to indicate that something went horribly wrong, which the caller can’t be expected to handle.

Rod Johnson còn đề xuất cả một hướng dẫn cụ thể:

Question Example Recommendation if the answer is yes
Should all callers handle this problem? Is the exception essentially a second return value for the method? Spending limit exceeded in a processInvoice() method Define and used a checked exception and take advantage of Java’s compile-time support.
Will only a minority of callers want to handle this problem? JDO exceptions Extend RuntimeException. This leaves callers the choice of catching the exception, but doesn’t force all callers to catch it.
Did something go horribly wrong? Is the problem unrecoverable? A business method fails because it can’t connect to the application database Extend RuntimeException. We know that callers can’t do anything useful besides inform the user of the error.
Still not clear?   Extend RuntimeException. Document the exceptions that may be thrown and let callers decide which, if any, they wish to catch.

Decide at a package level how each package will use checked or unchecked exceptions. Document the decision to use unchecked exceptions, as many developers will not expect it.

The only danger in using unchecked exceptions is that the exceptions may be inadequately documented. When using unchecked exceptions, be sure to document all exceptions that may be thrown from each method, allowing calling code to choose to catch even exceptions that you expect will be fatal. Ideally, the compiler should enforce Javdoc-ing of all exceptions, checked and unchecked.

If allocating resources such as JDBC connections that must be released under all circumstances, remember to use a finally block to ensure cleanup, whether or not you need to catch checked exceptions. Remember that a finally block can be used even without a catch block.

Quyển J2EE Design and Development còn trình bày rất nhiều về exception và các vấn đề đáng quan tâm khác trong Java.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s