对检查exception的情况

多年来,我一直无法得到一个像样的答案:为什么有些开发人员如此反对检查exception? 我经历了很多次的交谈,在博客上阅读,读了布鲁斯·艾克尔(Bruce Eckel)所说的话(我看到的第一个人对他们说的话)。

我目前正在写一些新的代码,并非常小心地注意我如何处理exception。 我试图看到“我们不喜欢被检查的例外”的观点,我仍然看不到它。

每一次谈话结束时都会有同样的问题没有答案…让我来设置它:

一般来说(从Java如何devise),

  • 错误是不应该被捕获的事情(VM有一个花生过敏,有人扔了一jar花生)
  • RuntimeException是程序员做错的事情(程序员离开数组的末尾)
  • exception(RuntimeException除外)是指程序员无法控制的事情(在写入文件系统时磁盘已满,已达到进程的文件句柄限制,您无法再打开任何文件)
  • Throwable只是所有exceptiontypes的父项。

我听到的一个共同的观点是,如果发生exception,那么所有开发人员将要做的就是退出程序。

我听到的另一个常见的观点是,检查exception使得重构代码变得更加困难。

对于“我要做的就是退出”的论点,我说即使你退出,你也需要显示一个合理的错误信息。 如果您只是在处理错误,那么当程序退出时,您的用户不会过于高兴,而没有明确指出原因。

对于“重构难以重构”的人群来说,这表明没有select适当的抽象层次。 IOException不应该声明方法抛出IOException,而应该将IOException转换为更适合正在发生的exception。

我没有用catch(Exception)(或者在某些情况下catch(Throwable)来包装Main以确保程序可以正常退出 – 但是我总是会捕获我需要的特定的exception。这样做可以让我,至less要显示一个合适的错误信息。

人们从不回答的问题是:

如果抛出RuntimeException子类而不是Exception子类,那么你怎么知道你应该捕获什么呢?

如果答案是catch Exception,那么你也像处理系统exception一样处理程序员错误。 这对我来说似乎是错误的。

如果你捕获Throwable,那么你正在以同样的方式处理系统exception和VM错误(等等)。 这对我来说似乎是错误的。

如果答案是你只捕获了你所知道的exception,那么你怎么知道抛出的是什么? 当程序员X抛出一个新的exception并忘记捕捉它时会发生什么? 这对我来说似乎非常危险。

我会说一个显示堆栈跟踪的程序是错误的。 那些不喜欢检查exception的人不会有这种感觉吗?

所以,如果你不喜欢检查的exception,你可以解释为什么不是和回答没有得到回答的问题吗?

编辑:我没有寻找什么时候使用任何模型的build议,我在寻找的是为什么人们从RuntimeException延伸,因为他们不喜欢从exception扩展和/或为什么他们捕获一个exception,然后重新抛出一个RuntimeException而不是添加抛出他们的方法。 我想了解不喜欢检查exception的动机。

我想我读了你所做过的同样的布鲁斯·艾克尔(Bruce Eckel)采访 – 而且总是让我感到困扰。 事实上,这个观点是由受访者(如果这确实是你正在谈论的文章)提出的,Anders Hejlsberg是.NET和C#背后的MS天才。

http://www.artima.com/intv/handcuffs.html

范虽然我是Hejlsberg和他的工作,但这个说法总是让我觉得自己是假的。 基本上归结为:

“被检查的exception是不好的,因为程序员通过总是捕获它们并且忽略它们来滥用它们,从而导致隐藏和忽略将被呈现给用户的问题”。

通过“否则呈现给用户”我的意思是,如果你使用一个运行时exception,懒惰的程序员将忽略它(而不是捕捉一个空的catch块),用户将看到它。

这个论点总结的总结是“程序员不能正确使用它们,不恰当地使用它们比不具有它们更糟糕”

这个论点有一些道理,实际上我怀疑Goslings没有把操作符replace成Java的动机来自于类似的争论 – 他们混淆了程序员,因为他们经常被滥用。

但是最终我认为这是Hejlsberg的一个虚假的争论,可能是一个事后的争论,是为了解释缺乏的,而不是一个深思熟虑的决定。

我认为,虽然检查exception的过度使用是一件坏事,而且往往会导致用户的粗暴处理,但正确使用它们可以让API程序员给API客户端程序员带来很大的好处。

现在,API程序员必须小心,不要把检查过的exception全部扔到这个地方,否则他们会干扰客户端程序员。 非常懒惰的客户端程序员会诉诸捕捉(Exception) {}正如Hejlsberg所警告的,所有的好处将会消失,地狱也会随之而来。 但是在某些情况下,只有一个很好的检查exception是不可替代的。

对我来说,经典的例子是文件打开的API。 语言历史上的每一种编程语言(至less在文件系统上)都有一个可以让你打开一个文件的API。 而且每个使用这个API的客户端程序员都知道他们必须处理他们试图打开的文件不存在的情况。 让我改述一下:每个使用这个API的客户端程序员都应该知道他们必须处理这种情况。 还有一个问题:API程序员是否可以帮助他们知道他们应该通过单独评论来处理这个问题,或者他们是否可以坚持要求客户处理这个问题。

在C中,这个习语就像是一样

  if (f = fopen("goodluckfindingthisfile")) { ... } else { // file not found ... 

fopen通过返回0和C来表示失败(愚蠢地)让你把0当作一个布尔值,…基本上你学习了这个习惯用法,你没事。 但是,如果你是一个noob,你没有学习这个成语。 那么当然你开始

  f = fopen("goodluckfindingthisfile"); f.read(); // BANG! 

并学习困难的方式。

请注意,我们只在这里讨论强types语言:对于强types语言中的API有一个清晰的概念:它是一个function(方法)的大杂烩,供您为每个语言使用明确定义的协议。

明确定义的协议通常由方法签名定义。 这里fopen要求你传递一个string(或者是C中的char *)。 如果你给它别的东西,你会得到一个编译时错误。 你没有遵循协议 – 你没有正确使用API​​。

在一些(模糊的)语言中,返回types也是协议的一部分。 如果你试图在某些语言中调用fopen()的等价物而不把它分配给一个variables,那么你也会得到一个编译时错误(你只能用void函数来做)。

我试图做的一点是: 在静态types的语言中,API程序员鼓励客户端正确使用API​​,通过防止他们的客户端代码编译,如果它有任何明显的错误。

(在像Ruby这样的dynamictypes语言中,你可以传递任何东西,比如float,作为文件名 – 并且它会被编译,为什么如果你甚至不去控制方法参数,那么用户检查exception是很麻烦的。这里提出的参数只适用于静态types的语言。)

那么,检查exception呢?

那么这里是您可以用来打开文件的Java API之一。

 try { f = new FileInputStream("goodluckfindingthisfile"); } catch (FileNotFoundException e) { // deal with it. No really, deal with it! ... // this is me dealing with it } 

看到这个问题? 以下是该API方法的签名:

 public FileInputStream(String name) throws FileNotFoundException 

请注意, FileNotFoundException是一个检查的exception。

API程序员对你这样说:“你可以用这个构造函数来创build一个新的FileInputStream

a) 必须以stringforms传递文件名
b) 必须接受在运行时可能找不到该文件的可能性“

就我而言,这就是整个问题。

关键基本上是这个问题所说的“不在程序员控制之下的东西”。 我的第一个想法是他/她意味着API程序员无法控制的东西。 但事实上,正确使用时检查exception应该是客户端程序员和API程序员无法控制的东西。 我认为这是不滥用检查exception的关键。

我认为文件打开很好地说明了这一点。 API程序员知道你可能会给他们一个文件名,在调用API的时候这个文件名是不存在的,他们将不能够返回你想要的东西,但是必须抛出一个exception。 他们也知道这种情况会经常发生,客户程序员可能会希望在编写调用的时候文件名是正确的,但是在运行时可能会出错,因为他们无法控制。

所以API明确表示:在你给我打电话的时候会有这个文件不存在的情况,而且你可以更好地处理它。

反案情况会更清楚。 想象一下,我正在写一个表API。 我有一个包含此方法的API的表模型:

 public RowData getRowData(int row) 

现在作为一个API程序员,我知道在某些情况下,某些客户端在表格外传递一个负值的行或行值。 所以我可能会试图抛出一个检查exception,并强制客户端处理它:

 public RowData getRowData(int row) throws CheckedInvalidRowNumberException 

(我当然不会真的叫它“检查”。)

这是使用已检查的exception。 客户端代码将充满调用来获取行数据,其中每一个都将不得不使用try / catch,为什么? 他们是否要向用户报告错误的行被寻找? 可能不会 – 因为无论我的表视图周围的用户界面是什么,它不应该让用户进入一个非法行被请求的状态。 所以这是客户端程序员的一个错误。

API程序员仍然可以预测客户端将编写这样的错误,并且应该像IllegalArgumentException那样处理运行时exception。

getRowData检查exception,这显然会导致Hejlsberg懒惰的程序员简单地添加空捕获。 当发生这种情况时,即使对testing人员或客户开发人员的debugging,非法的行值也不会很明显,相反他们会导致难以找出来源的连锁错误。 阿里安娜火箭发射后将炸毁。

好的,这里是问题所在:我在说,检查的exceptionFileNotFoundException不仅仅是一件好事,而是API程序员工具箱中用于为客户端程序员定义API的一个重要工具。 但CheckedInvalidRowNumberException是一个很大的不便,导致编程不好,应该避免。 但是如何区分这个区别呢。

我想这不是一个确切的科学,我猜这是潜在的,也许在一定程度上certificateHejlsberg的论点。 但我并不乐意把这个婴儿扔出去,所以让我在这里提取一些规则来区分良好的检查exception和不良:

  1. 脱离客户的控制或closures与打开:

    只有在错误情况不受API 客户端程序员控制的情况下才能使用检查exception。 这与系统如何打开closures有关。 在客户端程序员控制的受约束的 UI中,例如,在表视图(封闭系统)中添加和删除行的所有button,键盘命令等,如果它试图从数据库中获取数据一个不存在的行。 在任何数量的用户/应用程序可以添加和删除文件的基于文件的操作系统(开放系统)中,可以想象的是,客户请求的文件在他们不知情的情况下被删除,所以他们应该被期望处理它。

  2. 无处不在:

    检查exception不应该在客户端经常使用的API调用中使用。 我经常指的是来自客户端代码中的很多地方 – 不经常及时。 所以客户端代码并不倾向于尝试打开相同的文件,但我的表视图从不同的方法获取RowData 。 特别是我会写很多代码

     if (model.getRowData().getCell(0).isEmpty()) 

    每次都要在try / catch中包装会很痛苦。

  3. 通知用户:

    在您可以想象出一个有用的错误消息呈现给最终用户的情况下,应该使用检查的exception。 这是“什么时候发生?” 我上面提出的问题。 它也涉及到项目1.既然你可以预测,你的client-API系统之外的东西可能会导致文件不在那里,你可以合理地告诉用户:

     "Error: could not find the file 'goodluckfindingthisfile'" 

    由于您的非法行号是由内部错误引起的,并且没有用户的错误,所以实际上没有任何有用的信息可以提供给您。 如果您的应用程序不让运行时exception落入控制台,那么最终可能会给他们一些丑陋的消息,如:

     "Internal error occured: IllegalArgumentException in ...." 

    简而言之,如果你不认为你的客户端程序员可以以帮助用户的方式解释你的exception,那么你可能不应该使用检查的exception。

所以那些是我的规则。 有些做作,而且无疑会有例外(如果你愿意的话,请帮助我改进它们)。 但我的主要观点是,有像FileNotFoundException这样的情况,其中检查的exception与参数types一样重要且有用的API合约的一部分。 所以我们不应该因为滥用而放弃它。

对不起,这并不意味着要这么长时间和waffly。 让我完成两个build议:

答:API程序员:谨慎使用检查的exception来保持其有用性。 如有疑问,请使用未经检查的例外。

B:客户端程序员:习惯于在开发早期创build一个包装的exception(google)。 JDK 1.4及更高版本在RuntimeException中为此提供了一个构造函数,但是您也可以轻松创build自己的构造函数。 这里是构造函数:

 public RuntimeException(Throwable cause) 

然后养成习惯,每当你必须处理一个检查的exception,并且你感觉懒惰(或者你认为API程序员在使用被检查的exception时过于热心),不要只是吞下exception,并重新抛出它。

 try { overzealousAPI(thisArgumentWontWork); } catch (OverzealousCheckedException exception) { throw new RuntimeException(exception); } 

把它放在你的一个IDE的小代码模板中,当你感觉懒惰的时候使用它。 这样,如果你真的需要处理被检查的exception,你将在运行时看到问题后被迫回来处理它。 因为,相信我(和安德斯海耶斯伯格),你永远不会回到你的TODO

 catch (Exception e) { /* TODO deal with this at some point (yeah right) */} 

关于检查exception的事情是,通过对这个概念的一般理解,它们并不是真正的例外。 相反,他们是API替代返回值。

例外的整个想法是,在调用链的某个位置抛出的错误可能会冒起来,并被代码的某处进一步处理,而干预的代码不必担心。 另一方面,检查exception要求投掷者和捕捉者之间的每一层代码都声明他们知道可以通过它们的所有forms的exception。 如果检查的exception仅仅是调用者必须检查的特殊返回值,那么在实践中这与实际上是很不一样的。 例如[伪]:

 public [int or IOException] writeToStream(OutputStream stream) { [void or IOException] a= stream.write(mybytes); if (a instanceof IOException) return a; return mybytes.length; } 

由于Java不能做替代的返回值,或者简单的内联元组作为返回值,所以检查的exception是合理的响应。

问题在于很多代码,包括标准库的大部分代码,都会错误地检查exception情况,以便发现真正的exception情况,这些情况很可能要抓住几个层次。 为什么IOException不是RuntimeException? 在其他语言中,我可以让IOexception发生,如果我什么都不做,我的应用程序将停止,我会得到一个方便的堆栈跟踪来看看。 这是可能发生的最好的事情。

也许有两种方法可以从整个写入到stream的过程中捕获所有的IOExceptions,放弃进程并跳转到错误报告代码中; 在Java中,如果不在每个调用级别添加“throws IOException”,则不能这样做,即使它们本身没有IO也是如此。 这种方法不需要知道exception处理; 必须添加例外签名:

  1. 不必要地增加耦合;
  2. 使界面签名变得非常脆弱;
  3. 使代码更不可读;
  4. 是非常烦人的,它是常见的程序员的反应是通过做一些可怕的事情,像“抛出exception”,“catch(Exception e){}”,或者把所有东西包装在RuntimeException中(这使得debugging更困难)来打败系统。

然后有很多荒谬的图书馆例外,如:

 try { httpconn.setRequestMethod("POST"); } catch (ProtocolException e) { throw new CanNeverHappenException("oh dear!"); } 

当你不得不像这样荒谬的弄脏你的代码时,难怪检查exception会受到一堆仇恨,尽pipe真的这只是简单的糟糕的APIdevise。

另一个特别的不好的影响是控制反转(Inversion of Control),其中组件A向通用组件B提供callback。组件A希望能够使exception从它的callback抛回到它称为组件B的地方,但是它不能因为这会改变由B修复的callback接口。只能通过将真正的exception包装在一个RuntimeException中,这是更多的exception处理样板来编写的。

在Java中实现的检查exception及其标准库意味着样板,样板,样板。 在一个已经冗长的语言中,这不是一个胜利。

而不是重复所有(许多)原​​因反对检查exception,我会select一个。 我已经失去了我写这段代码的次数:

 try { // do stuff } catch (AnnoyingcheckedException e) { throw new RuntimeException(e); } 

99%的时间我不能做任何事情。 最后块做任何必要的清理(或至less他们应该)。

我也失去了我看过的次数:

 try { // do stuff } catch (AnnoyingCheckedException e) { // do nothing } 

为什么? 因为有人不得不处理,而且很懒惰。 错了吗? 当然。 这是否发生? 绝对。 如果这是一个未经检查的例外呢? 该应用程序将会死亡(这是吞咽exception更好)。

然后我们使用exception作为stream量控制的forms,如java.text.Format所做的代码。 Bzzzt。 错误。 将“abc”放入表单上的数字字段的用户并不例外。

好吧,我想这是三个原因。

那么,这不是显示一个堆栈跟踪或无声的崩溃。 这是关于能够沟通层之间的错误。

检查exception的问题是鼓励人们吞下重要的细节(即exception类)。 如果您select不要吞下这个细节,那么您必须在整个应用程序中不断添加抛出声明。 这意味着1)一个新的exceptiontypes会影响很多的function签名,2)你可能会错过一个特定的exception实例 – 你将要捕获的exception(比如说你打开一个函数的辅助文件来写数据到文件,第二个文件是可选的,所以你可以忽略它的错误,但是因为签名throws IOException ,所以很容易忽略这个)。

我实际上是在应用程序中处理这种情况。 我们重新封装了几乎所有的exception,如AppSpecificException。 这使得签名非常干净,我们不必担心签名中的爆炸。

当然,现在我们需要专门处理更高层次的error handling,实现重试逻辑等等。 但是,一切都是AppSpecificException,所以我们不能说“如果抛出一个IOException,重试”或“如果抛出ClassNotFound,则完全中止”。 我们没有一个可靠的方法来获得真正的例外,因为在我们的代码和第三方代码之间传递时,事情会一再重新打包。

这就是为什么我是python中的exception处理的大粉丝。 你只能捕捉你想要和/或可以处理的事情。 其他的一切都会起泡,好像你自己重新开始(反正你已经这样做了)。

我一次又一次地发现,在我提到的整个项目中,exception处理分为三类:

  1. 捕捉并处理特定的exception。 例如,这是为了实现重试逻辑。
  2. 捕捉并重新抛出其他例外。 这里发生的所有事情通常都是日志logging,通常是一个陈腐的消息,比如“无法打开$ filename”。 这些错误是你无法做任何事情的; 只有更高的层次才能够处理这个问题。
  3. 抓住一切,并显示一条错误消息。 这通常在调度程序的根本,它确保它可以通过非exception机制(popup对话框,编组RPC错误对象等)将错误传递给调用者。

我知道这是一个古老的问题,但我花了一段时间与检查exception摔跤,我有一些东西补充。 请原谅我的长度!

我检查exception的主要原因是他们破坏了多态性。 使用多态接口可以很好地发挥它们是不可能的。

拿好Java List界面。 我们有共同的内存中的实现像ArrayListLinkedList 。 我们也有骨架类AbstractList ,它可以很容易地devise新的列表types。 对于只读列表,我们只需要实现两个方法: size()get(int index)

这个例子WidgetList类从一个文件中读取Widgettypes的一些固定大小的对象(未示出):

 class WidgetList extends AbstractList<Widget> { private static final int SIZE_OF_WIDGET = 100; private final RandomAccessFile file; public WidgetList(RandomAccessFile file) { this.file = file; } @Override public int size() { return (int)(file.length() / SIZE_OF_WIDGET); } @Override public Widget get(int index) { file.seek((long)index * SIZE_OF_WIDGET); byte[] data = new byte[SIZE_OF_WIDGET]; file.read(data); return new Widget(data); } } 

通过使用熟悉的List接口公开Widget,您可以检索项目( list.get(123) )或迭代列表( for (Widget w : list) ... ),而无需了解WidgetList本身。 可以将此列表传递给使用generics列表的任何标准方法,也可以将其包装在Collections.synchronizedList 。 使用它的代码既不需要知道也不关心“Widget”是由现场组成,来自数组,还是从文件,数据库,networking或未来的子空间中继中读取。 它仍然会正常工作,因为List接口是正确实现的。

除外。 上面的类不会编译,因为文件访问方法可能会抛出一个IOExceptionexception,这是您必须“捕获或指定”的检查exception。 你不能指定它抛出 – 编译器不会让你因为这将违反List界面的合同。 WidgetList本身不能处理exception,这是没有用的方法(正如我将在后面阐述的那样)。

显然唯一要做的就是将检查的exception捕获并重新抛出一些未经检查的exception:

 @Override public int size() { try { return (int)(file.length() / SIZE_OF_WIDGET); } catch (IOException e) { throw new WidgetListException(e); } } public static class WidgetListException extends RuntimeException { public WidgetListException(Throwable cause) { super(cause); } } 

(编辑:Java 8已经为这种情况添加了一个UncheckedIOException类:用于在多态方法边界上捕获和重新抛出IOException s,这种certificatecertificate了我的观点!)

因此,检查exception在这种情况下不起作用 。 你不能扔他们。 数据库支持的智能Map同上,或通过COM端口连接到量子熵源的java.util.Random实现。 只要尝试使用多态接口来实现新颖性,检查exception的概念就会失败。 但检查exception是如此阴险,以至于他们仍然不会离开你,因为你仍然需要捕捉和重新抛出低级别的方法,混淆代码和混乱堆栈跟踪。

我发现,无处不在的Runnable接口通常被支持到这个angular落,如果它调用引发检查exception的东西。 它不能像现在那样抛出exception,所以它只能通过捕获和重新抛出RuntimeException混淆代码。

事实上,如果你诉诸黑客,你可以抛出未申报的检查exception。 JVM在运行时并不关心检查的exception规则,所以我们只需要愚弄编译器。 最简单的方法就是滥用generics。 这是我的方法(显示的类名称,因为(在Java 8之前)在generics方法的调用语法中需要它):

 class Util { /** * Throws any {@link Throwable} without needing to declare it in the * method's {@code throws} clause. * * <p>When calling, it is suggested to prepend this method by the * {@code throw} keyword. This tells the compiler about the control flow, * about reachable and unreachable code. (For example, you don't need to * specify a method return value when throwing an exception.) To support * this, this method has a return type of {@link RuntimeException}, * although it never returns anything. * * @param t the {@code Throwable} to throw * @return nothing; this method never returns normally * @throws Throwable that was provided to the method * @throws NullPointerException if {@code t} is {@code null} */ public static RuntimeException sneakyThrow(Throwable t) { return Util.<RuntimeException>sneakyThrow1(t); } @SuppressWarnings("unchecked") private static <T extends Throwable> RuntimeException sneakyThrow1( Throwable t) throws T { throw (T)t; } } 

欢呼! 使用这个方法,我们可以在没有声明的情况下抛出一个检查exception的深度,没有将它包装在一个RuntimeException ,而且不会混乱堆栈跟踪! 再次使用“WidgetList”示例:

 @Override public int size() { try { return (int)(file.length() / SIZE_OF_WIDGET); } catch (IOException e) { throw sneakyThrow(e); } } 

不幸的是,检查exception的最终侮辱是编译器拒绝允许你捕获一个检查的exception,如果其有缺陷的意见,它不能被抛出。 (未经检查的exception没有这个规则。)为了捕捉这个被抛出的exception,我们必须这样做:

 try { ... } catch (Throwable t) { // catch everything if (t instanceof IOException) { // handle it ... } else { // didn't want to catch this one; let it go throw t; } } 

这有点尴尬,但从正面来看,它比解压缩包含在RuntimeException的checkedexception的代码稍微简单一些。

令人高兴的是, throw t; 语句在这里是合法的,即使检查了t的types,这要归功于Java 7中添加的关于重新抛出捕获的exception的规则。


当检查exception满足多态性时,相反的情况也是一个问题:当一个方法被指定为可能抛出一个检查的exception,但重写的实现不会。 例如,抽象类OutputStreamwrite方法都指定throws IOExceptionByteArrayOutputStream是写入内存数组而不是真正的I / O源的子类。 其重写的write方法不会导致IOException ,因此它们没有throws子句,您可以调用它们而不必担心catch-or-specify的要求。

除了不总是。 假设Widget有一个将其保存到stream中的方法:

 public void writeTo(OutputStream out) throws IOException; 

声明这个方法接受一个普通的OutputStream是正确的事情,所以它可以被多forms地用于各种输出:文件,数据库,networking等等。 和内存数组。 但是,对于内存数组,有一个虚假的要求来处理一个实际上不可能发生的exception:

 ByteArrayOutputStream out = new ByteArrayOutputStream(); try { someWidget.writeTo(out); } catch (IOException e) { // can't happen (although we shouldn't ignore it if it does) throw new RuntimeException(e); } 

像往常一样,检查的exception阻碍。 If your variables are declared as a base type that has more open-ended exception requirements, you have to add handlers for those exceptions even if you know they won't occur in your application.

But wait, checked exceptions are actually so annoying, that they won't even let you do the reverse! Imagine you currently catch any IOException thrown by write calls on an OutputStream , but you want to change the variable's declared type to a ByteArrayOutputStream , the compiler will berate you for trying to catch a checked exception that it says cannot be thrown.

That rule causes some absurd problems. For example, one of the three write methods of OutputStream is not overridden by ByteArrayOutputStream . Specifically, write(byte[] data) is a convenience method that writes the full array by calling write(byte[] data, int offset, int length) with an offset of 0 and the length of the array. ByteArrayOutputStream overrides the three-argument method but inherits the one-argument convenience method as-is. The inherited method does exactly the right thing, but it includes an unwanted throws clause. That was perhaps an oversight in the design of ByteArrayOutputStream , but they can never fix it because it would break source compatibility with any code that does catch the exception — the exception that has never, is never, and never will be thrown!

That rule is annoying during editing and debugging too. Eg, sometimes I'll comment out a method call temporarily, and if it could have thrown a checked exception, the compiler will now complain about the existence of the local try and catch blocks. So I have to comment those out too, and now when editing the code within, the IDE will indent to the wrong level because the { and } are commented out. Gah! It's a small complaint but it seems like the only thing checked exceptions ever do is cause trouble.


I'm nearly done. My final frustration with checked exceptions is that at most call sites , there's nothing useful you can do with them. Ideally when something goes wrong we'd have a competent application-specific handler that can inform the user of the problem and/or end or retry the operation as appropriate. Only a handler high up the stack can do this because it's the only one that knows the overall goal.

Instead we get the following idiom, which is rampant as a way to shut the compiler up:

 try { ... } catch (SomeStupidExceptionOmgWhoCares e) { e.printStackTrace(); } 

In a GUI or automated program the printed message won't be seen. Worse, it plows on with the rest of the code after the exception. Is the exception not actually an error? Then don't print it. Otherwise, something else is going to blow up in a moment, by which time the original exception object will be gone. This idiom is no better than BASIC's On Error Resume Next or PHP's error_reporting(0);

Calling some kind of logger class is not much better:

 try { ... } catch (SomethingWeird e) { logger.log(e); } 

That is just as lazy as e.printStackTrace(); and still plows on with code in an indeterminate state. Plus, the choice of a particular logging system or other handler is application-specific, so this hurts code reuse.

可是等等! There is an easy and universal way to find the application-specific handler. It's higher up the call stack (or it is set as the Thread's uncaught exception handler ). So in most places, all you need to do is throw the exception higher up the stack . Eg, throw e; 。 Checked exceptions just get in the way.

I'm sure checked exceptions sounded like a good idea when the language was designed, but in practice I've found them to be all bother and no benefit.

Artima published an interview with one of the architects of .NET, Anders Hejlsberg, which acutely covers the arguments against checked exceptions. A short taster:

The throws clause, at least the way it's implemented in Java, doesn't necessarily force you to handle the exceptions, but if you don't handle them, it forces you to acknowledge precisely which exceptions might pass through. It requires you to either catch declared exceptions or put them in your own throws clause. To work around this requirement, people do ridiculous things. For example, they decorate every method with, "throws Exception." That just completely defeats the feature, and you just made the programmer write more gobbledy gunk. That doesn't help anybody.

简而言之:

Exceptions are an API design question. — No more, no less.

The argument for checked exceptions:

To understand why checked exceptions might not be good thing, let's turn the question around and ask: When or why are checked exceptions attractive, ie why would you want the compiler to enforce declaration of exceptions?

The answer is obvious: Sometimes you need to catch an exception, and that is only possible if the code being called offers a specific exception class for the error that you are interested in.

Hence, the argument for checked exceptions is that the compiler forces programmers to declare which exceptions are thrown, and hopefully the programmer will then also document specific exception classes and the errors that cause them.

In reality though, ever too often a package com.acme only throws an AcmeException rather than specific subclasses. Callers then need to handle, declare, or re-signal AcmeExceptions , but still cannot be certain whether an AcmeFileNotFoundError happened or an AcmePermissionDeniedError .

So if you're only interested in an AcmeFileNotFoundError , the solution is to file a feature request with the ACME programmers and tell them to implement, declare, and document that subclass of AcmeException .

So why bother?

Hence, even with checked exceptions, the compiler cannot force programmers to throw useful exceptions. It is still just a question of the API's quality.

As a result, languages without checked exceptions usually do not fare much worse. Programmers might be tempted to throw unspecific instances of a general Error class rather than an AcmeException , but if they care at all about their API quality, they will learn to introduce an AcmeFileNotFoundError after all.

Overall, the specification and documentation of exceptions is not much different from the specification and documentation of, say, ordinary methods. Those, too, are an API design question, and if a programmer forgot to implement or export a useful feature, the API needs to be improved so that you can work with it usefully.

If you follow this line of reasoning, it should be obvious that the "hassle" of declaring, catching, and re-throwing of exceptions that is so common in languages like Java often adds little value.

It is also worth noting that the Java VM does not have checked exceptions — only the Java compiler checks them, and class files with changed exception declarations are compatible at run time. Java VM security is not improved by checked exceptions, only coding style.

SNR

Firstly, checked exceptions decrease the "signal-to-noise ratio" for the code. Anders Hejlsberg also talks about imperative vs declarative programming which is a similar concept. Anyway consider the following code snippets:

Update UI from non UI-thread in Java:

 try { // Run the update code on the Swing thread SwingUtilities.invokeAndWait(() -> { try { // Update UI value from the file system data FileUtility f = new FileUtility(); uiComponent.setValue(f.readSomething()); } catch (IOException e) { throw new UncheckedIOException(e); } }); } catch (InterruptedException ex) { throw new IllegalStateException("Interrupted updating UI", ex); } catch (InvocationTargetException ex) { throw new IllegalStateException("Invocation target exception updating UI", ex); } 

Update UI from non UI-thread in C#:

 private void UpdateValue() { // Ensure the update happens on the UI thread if (InvokeRequired) { Invoke(new MethodInvoker(UpdateValue)); } else { // Update UI value from the file system data FileUtility f = new FileUtility(); uiComponent.Value = f.ReadSomething(); } } 

Which seems a lot clearer to me. When you start to do more and more UI work in Swing checked exceptions start to become really annoying and useless.

Jail Break

To implement even the most basic of implementations, such as Java's List interface, checked exceptions as a tool for design by contract fall down. Consider a list that is backed by a database or a filesystem or any other implementation that throws a checked exception. The only possible implementation is to catch the checked exception and rethrow it as an unchecked exception:

 @Override public void clear() { try { backingImplementation.clear(); } catch (CheckedBackingImplException ex) { throw new IllegalStateException("Error clearing underlying list.", ex); } } 

And now you have to ask what is the point of all that code? The checked exceptions just add noise, the exception has been caught but not handled and design by contract (in terms of checked exceptions) has broken down.

结论

  • Catching exceptions is different to handling them.
  • Checked exceptions add noise to the code.
  • Exception handling works well in C# without them.

I blogged about this previously .

I initially agreed with you, as I've always been in favour of checked exceptions, and began to think about why I don't like not having checked exceptions in .Net. But then I realised that I don't infact like checked exceptions.

To answer you question, yes, I like my programs to show stack traces, preferably really ugly ones. I want the application to explode into a horrible heap of the ugliest error messages you could ever want to see.

And the reason is because, if it does that, I have to fix it, and I have to fix it right away. I want to know immediately that there is a problem.

How many times do you actually handle exceptions? I'm not talking about catching exceptions — I'm talking about handling them? It's too easy to write the following:

 try { thirdPartyMethod(); } catch(TPException e) { // this should never happen } 

And I know you can say that it's bad practice, and that 'the answer' is to do something with the exception (let me guess, log it?), but in the Real World ™, most programmers just don't do it.

So yes, I don't want to catch exceptions if I don't have to do so, and I want my program to blow up spectacularly when I screw up. Silently failing is the worst possible outcome.

The article Effective Java Exceptions explains nicely when to use unchecked and when to use checked exceptions. Here are some quotes from that article to highlight the main points:

Contingency: An expected condition demanding an alternative response from a method that can be expressed in terms of the method's intended purpose. The caller of the method expects these kinds of conditions and has a strategy for coping with them.

Fault: An unplanned condition that prevents a method from achieving its intended purpose that cannot be described without reference to the method's internal implementation.

(SO doesn't allow tables, so you might want to read the following from the original page …)

偶然性

  • Is considered to be: A part of the design
  • Is expected to happen: Regularly but rarely
  • Who cares about it: The upstream code that invokes the method
  • Examples: Alternative return modes
  • Best Mapping: A checked exception

Fault

  • Is considered to be: A nasty surprise
  • Is expected to happen: Never
  • Who cares about it: The people who need to fix the problem
  • Examples: Programming bugs, hardware malfunctions, configuration mistakes, missing files, unavailable servers
  • Best Mapping: An unchecked exception

I have been working with several developers in the last three years in relatively complex applications. We have a code base that uses Checked Exceptions quite often with proper error handling, and some other that doesn't.

So far, I have it found easier to work with the code base with Checked Exceptions. When I am using someone else's API, it is nice that I can see exactly what kind of error conditions I can expect when I call the code and handle them properly, either by logging, displaying or ignoring (Yes, there is valid cases for ignoring exceptions, such as a ClassLoader implementation). That gives the code I am writing an opportunity to recover. All runtime exceptions I propagate up until they are cached and handled with some generic error handling code. When I find a checked exception that I don't really want to handle at a specific level, or that I consider a programming logic error, then I wrap it into a RuntimeException and let it bubble up. Never, ever swallow an exception without a good reason (and good reasons for doing this are rather scarce)

When I work with the codebase that does not have checked exceptions, it makes it to me a little bit harder to know before hand what can I expect when calling the function, which can break some stuff terribly.

This is all of course a matter of preference and developer skill. Both ways of programming and error handling can be equally effective (or noneffective), so I wouldn't say that there is The One Way.

All in all, I find it easier to work with Checked Exceptions, specially in large projects with lot of developers.

Exception categories

When talking about exceptions I always refer back to Eric Lippert's Vexing exceptions blog article. He places exceptions into these categories:

  • Fatal – These exceptions are not your fault : you cannot prevent then, and you cannot sensibly handle them. For example, OutOfMemoryError or ThreadAbortException .
  • Boneheaded – These exceptions are your fault : you should have prevented them, and they represent bugs in your code. For example, ArrayIndexOutOfBoundsException , NullPointerException or any IllegalArgumentException .
  • Vexing – These exceptions are not exceptional , not your fault, you cannot prevent them, but you'll have to deal with them. They are often the result of an unfortunate design decision, such as throwing NumberFormatException from Integer.parseInt instead of providing an Integer.tryParseInt method that returns a boolean false on parse failure.
  • Exogenous – These exceptions are usually exceptional , not your fault, you cannot (reasonably) prevent them, but you must handle them . For example, FileNotFoundException .

An API user:

  • must not handle fatal or boneheaded exceptions.
  • should handle vexing exceptions, but they should not occur in an ideal API.
  • must handle exogenous exceptions.

Checked exceptions

The fact that the API user must handle a particular exception is part of the method's contract between the caller and the callee. The contract specifies, among other things: the number and types of arguments the callee expects, the type of return value the caller can expect, and the exceptions the caller is expected to handle .

Since vexing exceptions should not exist in an API, only these exogenous exceptions must be checked exceptions to be part of the method's contract. Relatively few exceptions are exogenous , so any API should have relatively few checked exceptions.

A checked exception is an exception that must be handled . Handling an exception can be as simple as swallowing it. There! The exception is handled. 期。 If the developer wants to handle it that way, fine. But he can't ignore the exception, and has been warned.

API problems

But any API that has checked vexing and fatal exceptions (eg the JCL) will put unnecessary strain on the API users. Such exceptions have to be handled, but either the exception is so common that it should not have been an exception in the first place, or nothing can be done when handling it. And this causes Java developers to hate checked exceptions.

Also, many APIs don't have a proper exception class hierarchy, causing all kinds of non-exogenous exception causes to be represented by a single checked exception class (eg IOException ). And this also causes Java developers to hate checked exceptions.

结论

Exogenous exceptions are those that are not your fault, could not have been prevented, and which should be handled. These form a small subset of all the exceptions that can get thrown. APIs should only have checked exogenous exceptions , and all other exceptions unchecked. This will make better APIs, put less strain on the API user, and therefore reduce the need to catch all, swallow or rethrow unchecked exceptions.

So don't hate Java and its checked exceptions. Instead, hate the APIs that overuse checked exceptions.

Ok… Checked exceptions are not ideal and have some caveat but they do serve a purpose. When creating an API there are specific cases of failures that are contractual of this API. When in the context of a strongly statically typed language such as Java if one does not use checked exceptions then one must rely on ad-hoc documentation and convention to convey the possibility of error. Doing so removes all benefit that the compiler can bring in handling error and you are left completely to the good will of programmers.

So, one removes Checked exception, such as was done in C#, how then can one programmatically and structurally convey the possibility of error ? How to inform the client code that such and such errors can occur and must be dealt with ?

I hear all sorts of horrors when dealing with checked exceptions, they are misused this is certain but so are unchecked exceptions. I say wait a few years when APIs are stacked many layers deep and you will be begging for the return of some kind of structured mean to convey failures.

Take the case when the exception was thrown somewhere at the bottom of the API layers and just bubbled up because nobody knew it was even possible for this error to occur, this even though it was a type of error that was very plausible when the calling code threw it (FileNotFoundException for example as opposed to VogonsTrashingEarthExcept… in which case it would not matter if we handle it or not since there is nothing left to handle it with).

Many have argued that not being able to load the file was almost always the end of the world for the process and it must die a horrible and painful death. So yeah.. sure … ok.. you build an API for something and it loads file at some point… I as the user of said API can only respond… "Who the hell are you to decide when my program should crash !" Sure Given the choice where exceptions are gobbled up and leave no trace or the EletroFlabbingChunkFluxManifoldChuggingException with a stack trace deeper than the Marianna trench I would take the latter without a cinch of hesitation, but does this mean that it is the desirable way to deal with exception ? Can we not be somewhere in the middle, where the exception would be recast and wrapped each time it traversed into a new level of abstraction so that it actually means something ?

Lastly, most of the argument I see is "I don't want to deal with exceptions, many people do not want to deal with exceptions. Checked exceptions force me to deal with them thus I hate checked exception" To eliminate such mechanism altogether and relegate it to the chasm of goto hell is just silly and lacks jugement and vision.

If we eliminate checked exception we could also eliminate the return type for functions and always return a "anytype" variable… That would make life so much simpler now would it not ?

Anders speaks about the pitfalls of checked exceptions and why he left them out of C# in episode 97 of Software Engineering radio.

Indeed, checked exceptions on the one hand increase robustness and correctness of your program (you're forced to make correct declarations of your interfaces -the exceptions a method throws are basically a special return type). On the other hand you face the problem that, since exceptions "bubble up", very often you need to change a whole lot of methods (all the callers, and the callers of the callers, and so on) when you change the exceptions one method throws.

Checked exceptions in Java do not solve the latter problem; C# and VB.NET throw out the baby with the bathwater.

A nice approach that takes the middle road is described in this OOPSLA 2005 paper (or the related technical report .)

In short, it allows you to say: method g(x) throws like f(x) , which means that g throws all the exceptions f throws. Voila, checked exceptions without the cascading changes problem.

Although it is an academic paper, I'd encourage you to read (parts of) it, as it does a good job of explaining what the benefits and downsides of checked exceptions are.

问题

The worst problem I see with exception handling mechanism is that it introduces code duplication in a big scale ! Let's be honest: In most of projects in 95% of the time all that developers really need to do with exception is to communicate it somehow to the user (and, in some cases, to the development team as well, eg by sending an e-mail with the stack trace). So usually the same line/block of code is used in every place the exception is handled.

Let's assume that we do simple logging in each catch block for some type of checked exception:

 try{ methodDeclaringCheckedException(); }catch(CheckedException e){ logger.error(e); } 

If it's a common exception there may be even several hundreds of such try-catch blocks in a larger codebase. Now let's assume that we need to introduce popup dialog based exception handling instead of console logging or start to additionally send an e-mail to the development team.

Wait a moment… are we really going to edit all of that several hundreds of locations in the code?! You get my point :-).

解决scheme

What we did to adress that issue was introducing the concept of exception handlers (to which I'll further refer as EH's) to centralize exception handling. To every class that needs to hande exceptions an instance of exception handler is injected by our Dependency Injection framework. So the typical pattern of exception handling now looks like this:

 try{ methodDeclaringCheckedException(); }catch(CheckedException e){ exceptionHandler.handleError(e); } 

Now to customize our exception handling we only need to change the code in a single place (EH code).

Of course for more complex cases we can implement several subclasses of EHs and leverage features that our DI framework provides us. By changing our DI framework configuration we can easily switch EH implementation globally or provide specific implementations of EH to classes with special exception handling needs (for example using Guice @Named annotation).

That way we can differentiate exception handling behaviour in development and release version of application (eg. development – logging the error and halting the application, prod – logging the error with more details and letting the application continue its execution) with no effort.

Last one thing

Last but not least, it may seem that the same kind of centralisation can be obtained by just passing our exceptions "up" until they arrive to some top level exception handling class. But that leads to cluttering of code and signatures of our methods and introduces maintenance problems mentioned by others in this thread.

As folks have already stated, checked exceptions don't exist in Java bytecode. They are simply a compiler mechanism, not unlike other syntax checks. I see checked exceptions a lot like I see the compiler complaining about unreachable code at b : if(true) { a; } b; 。 That's helpful but I might have done this on purpose, so let me ignore your warnings.

The fact of the matter is, you aren't going to be able to force every programmer to "do the right thing" if you enforce checked exceptions and everyone else is now collateral damage who just hates you for the rule you made.

Fix the bad programs out there! Don't try to fix the language to not allow them! For most folks, "doing something about an exception" is really just telling the user about it. I can tell the user about an unchecked exception just as well, so keep your checked exception classes out of my API.

My writeup on c2.com is still mostly unchanged from its original form: CheckedExceptionsAreIncompatibleWithVisitorPattern

综上所述:

Visitor Pattern and its relatives are a class of interfaces where the indirect caller and interface implementation both know about an exception but the interface and direct caller form a library that cannot know.

The fundamental assumption of CheckedExceptions is all declared exceptions can be thrown from any point that calls a method with that declaration. The VisitorPattern reveals this assumption to be faulty.

The final result of checked exceptions in cases like these is a lot of otherwise useless code that essentially removes the compiler's checked exception constraint at runtime.

As for the underlying problem:

My general idea is the top-level handler needs to interpret the exception and display an appropriate error message. I almost always see either IO exceptions, communication exceptions (for some reason APIs distinguish), or task-fatal errors (program bugs or severe problem on backing server), so this should not be too hard if we allow a stack trace for a severe server problem.

To attempt to address just the unanswered question:

If you throw RuntimeException subclasses instead of Exception subclasses then how do you know what you are supposed to catch?

The question contains specious reasoning IMHO. Just because the API tells you what it throws doesn't mean you deal with it in the same way in all cases. To put it another way, the exceptions you need to catch vary depending on the context in which you use the component throwing the exception.

例如:

If I'm writing a connection tester for a database, or something to check the validity of a user entered XPath, then I'd probably want to catch and report on all checked and unchecked exceptions that are thrown by the operation.

If, however, I am writing a processing engine, I will likely treat an XPathException (checked) in the same way as an NPE: I would let it run up to the top of the worker thread, skip the rest of that batch, log the issue (or send it to a support department for diagnosis) and leave feedback for the user to contact support.

Here 's one argument against checked exceptions (from joelonsoftware.com):

The reasoning is that I consider exceptions to be no better than "goto's", considered harmful since the 1960s, in that they create an abrupt jump from one point of code to another. In fact they are significantly worse than goto's:

  • They are invisible in the source code. Looking at a block of code, including functions which may or may not throw exceptions, there is no way to see which exceptions might be thrown and from where. This means that even careful code inspection doesn't reveal potential bugs.
  • They create too many possible exit points for a function. To write correct code, you really have to think about every possible code path through your function. Every time you call a function that can raise an exception and don't catch it on the spot, you create opportunities for surprise bugs caused by functions that terminated abruptly, leaving data in an inconsistent state, or other code paths that you didn't think about.

This article is the best piece of text on exception handling in Java I have ever read.

It favours unchecked over checked exceptions but this choice is explained very thouroughly and based on strong arguments.

I don't want to cite too much of the article content here (it's best to read it as a whole) but it covers most of arguments of unchecked exceptions advocates from this thread. Especially this argument (which seems to be quite popular) is covered:

Take the case when the exception was thrown somewhere at the bottom of the API layers and just bubbled up because nobody knew it was even possible for this error to occur, this even though it was a type of error that was very plausible when the calling code threw it (FileNotFoundException for example as opposed to VogonsTrashingEarthExcept… in which case it would not matter if we handle it or not since there is nothing left to handle it with).

The author "responses":

It is absolutely incorrect to assume that all runtime exceptions should not be caught and allowed to propagate to the very "top" of the application. (…) For every exceptional condition that is required to be handled distinctly – by the system/business requirements – programmers must decide where to catch it and what to do once the condition is caught. This must be done strictly according to the actual needs of the application, not based on a compiler alert. All other errors must be allowed to freely propagate to the topmost handler where they would be logged and a graceful (perhaps, termination) action will be taken.

And the main thought or article is:

When it comes to error handling in software, the only safe and correct assumption that may ever be made is that a failure may occur in absolutely every subroutine or module that exists!

So if " nobody knew it was even possible for this error to occur " there is something wrong with that project. Such exception should be handled by at least the most generic exception handler (eg the one that handles all Exceptions not handled by more specific handlers) as author suggests.

So sad not many poeple seems to discover this great article :-(. I recommend wholeheartly everyone who hesitates which approach is better to take some time and read it.

A problem with checked exceptions is that exceptions are often attached to methods of an interface if even one implementation of that interface uses it.

Another problem with checked exceptions is that they tend to be misused. The perfect example of this is in java.sql.Connection 's close() method. It can throw a SQLException , even though you've already explicitly stated that you're done with the Connection. What information could close() possibly convey that you'd care about?

Usually, when I close() a connection * , it looks something like this:

 try { conn.close(); } catch (SQLException ex) { // Do nothing } 

Also, don't get me started on the various parse methods and NumberFormatException… .NET's TryParse, which doesn't throw exceptions, is so much easier to use it's painful to have to go back to Java (we use both Java and C# where I work).

* As an additional comment, a PooledConnection's Connection.close() doesn't even close a connection, but you still have to catch the SQLException due to it being a checked exception.

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.

One crucial point, 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.

If our application is not a DB.. we shouldn't try and fix the DB. That would violate the principle of encapsulation .

Particularly problematic have been 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.

The other severe flaw in the Java design, was that exception-handling should correctly placed at the highest possible "business" or "request" level. The principle here is "throw early, catch late". Checked exceptions do little but get in the way of this.

We have an obvious issue in Java of requiring thousands of do-nothing try-catch blocks, with a significant proportion (40%+) being miscoded. Almost none of these implement any genuine handling or reliability, but impose major coding overhead.

Lastly, "checked exceptions" are pretty much incompatible with FP functional programming.

Their insistence on "handle immediately" is at odds with both "catch late" exception-handling best practice, and any FP structure which abstracts loops/ or flow of control.

Many people talk about "handling" checked exceptions, but are talking through their hats. Continuing after a failure with null, incomplete or incorrect data to pretend success is not handling anything. It's engineering/ reliability malpractice of the lowest form.

Failing cleanly, is the most basic correct strategy for handling an exception. Rolling back the transaction, logging the error & reporting a "failure" response to the user are sound practice — and most importantly, prevent incorrect business data being committed to the database.

Other strategies for exception-handling are "retry", "reconnect" or "skip", at the business, subsystem, or request level. All of these are general reliability strategies, and work well/ better with runtime exceptions.

Lastly, it is far preferable to fail, than to run with incorrect data. Continuing will either cause secondary errors, distant from the original cause & harder to debug; or will eventually result in erroneous data being committed. People get fired for that.

看到:
http://literatejava.com/exceptions/checked-exceptions-javas-biggest-mistake/

I think that this is an excellent question and not at all argumentative. I think that 3rd party libraries should (in general) throw unchecked exceptions. This means that you can isolate your dependencies on the library (ie you don't have to either re-throw their exceptions or throw Exception – usually bad practice). Spring's DAO layer is an excellent example of this.

On the other hand, exceptions from the core Java API should in general be checked if they could ever be handled. Take FileNotFoundException or (my favourite) InterruptedException . These conditions should almost always be handled specifically (ie your reaction to an InterruptedException is not the same as your reaction to an IllegalArgumentException ). The fact that your exceptions are checked forces developers to think about whether a condition is handle-able or not. (That said, I've rarely seen InterruptedException handled properly!)

One more thing – a RuntimeException is not always "where a developer got something wrong". An illegal argument exception is thrown when you try and create an enum using valueOf and there's no enum of that name. This is not necessarily a mistake by the developer!

We've seen some references to C#'s chief architect.

Here's an alternate point of view from a Java guy about when to use checked exceptions. He acknowledges many of the negatives others have mentioned: Effective Exceptions

The good proves that Checked Exception are not needed are:

  1. A lot of framework that does some work for Java. Like Spring that wraps JDBC exception to unchecked exceptions, throwing messages to the log
  2. Lot of languages that came after java, even on top on java platform – they do not use them
  3. Checked exceptions, it is kind prediction about how the client would use the code that throws an exception. But a developer who writes this code would never know about the system and business that client of code is working in. As an example Interfcace methods that force to throw checked exception. There are 100 implementation over the system, 50 or even 90 of implementations do not throw this exception, but the client still must to catch this exception if he user reference to that interface. Those 50 or 90 implementations tend to handle those exceptions inside themself, putting exception to the log (and this is good behavior for them). What we should do with that? I would better have some background logic that would do all that job – sending message to the log. And If I, as a client of code, would feel I need handle the exception – I will do it. I may forget about it, right – but if I use TDD, all my steps are covered and I know what I want.
  4. Another example when I'm working with I/O in java, it forces me to check all exception, if file does not exists? what I should do with that? If it does not exists, the system would not go to the next step. The client of this method, would not get expected content from that file – he can handle Runtime Exception, otherwise I should first check Checked Exception, put a message to log, then throw exception up out form the method. No…no – I would better do it automatically with RuntimeEception, that does it / lits up automatically. There is no any sense to handle it manually – I would be happy I saw an error message in the log (AOP can help with that.. something that fixes java). If, eventually, I deice that system should shows pop-up message to the end user – I will show it, not a problem.

I was happy if java would provide me with a choice what to use, when working with core libs, like I/O. Like provides two copies of same classes – one wrapped with RuntimeEception. Then we can compare what people would use . For now, though, many people would better go for some framework on top on java, or different language. Like Scala, JRuby whatever. Many just believe that SUN was right.

Despite having read the whole page, I still can't find a single reasonable argument against checked exceptions. Most people are instead talking about poor API design, either at some Java classes or at their own classes.

The only scenario where this feature may be annoying is prototiping. This could be solved by adding some mechanism to the language (for instance, some @supresscheckedexceptions annotation). But for regular programming, I think checked exceptions are a good thing.

The programmer needs to know all of the exceptions that a method may throw, in order to use it correctly. So, beating him over the head with just some of the exceptions does not necessarily help a careless programmer avoid errors.

The slim benefit is outweighed by the burdensome cost (especially in larger, less flexible code bases where constantly modifying the interface signatures is not practical).

Static analysis can be nice, but truly reliable static analysis often inflexibly demands strict work from the programmer. There is a cost-benefit calculation, and the bar needs to be set high for a check that leads to a compile time error. It would be more helpful if the IDE took on the role of communicating which exceptions a method may throw (including which are unavoidable). Although perhaps it would not be as reliable without forced exception declarations, most exceptions would still be declared in documentation, and the reliability of an IDE warning is not so crucial.

This isn't an argument against the pure concept of checked exceptions, but the class hierarchy Java uses for them is a freak show. We always call the things simply "exceptions" – which is correct, because the language specification calls them that too – but how is an exception named and represented in the type system?

By the class Exception one imagines? Well no, because Exception s are exceptions, and likewise exceptions are Exception s, except for those exceptions that are not Exception s, because other exceptions are actually Error s, which are the other kind of exception, a kind of extra-exceptional exception that should never happen except when it does, and which you should never catch except sometimes you have to. Except that's not all because you can also define other exceptions that are neither Exception s nor Error s but merely Throwable exceptions.

Which of these are the "checked" exceptions? Throwable s are checked exceptions, except if they're also Error s, which are unchecked exceptions, and then there's the Exception s, which are also Throwable s and are the main type of checked exception, except there's one exception to that too, which is that if they are also RuntimeException s, because that's the other kind of unchecked exception.

What are RuntimeException s for? Well just like the name implies, they're exceptions, like all Exception s, and they happen at run-time, like all exceptions actually, except that RuntimeException s are exceptional compared to other run-time Exception s because they aren't supposed to happen except when you make some silly error, although RuntimeException s are never Error s, so they're for things that are exceptionally erroneous but which aren't actually Error s. Except for RuntimeErrorException , which really is a RuntimeException for Error s. But aren't all exceptions supposed to represent erroneous circumstances anyway? Yes, all of them. Except for ThreadDeath , an exceptionally unexceptional exception, as the documentation explains that it's a "normal occurrence" and that that's why they made it a type of Error .

Anyway, since we're dividing all exceptions down the middle into Error s (which are for exceptional execution exceptions, so unchecked) and Exception s (which are for less exceptional execution errors, so checked except when they're not), we now need two different kinds of each of several exceptions. So we need IllegalAccessError and IllegalAccessException , and InstantiationError and InstantiationException , and NoSuchFieldError and NoSuchFieldException , and NoSuchMethodError and NoSuchMethodException , and ZipError and ZipException .

Except that even when an exception is checked, there are always (fairly easy) ways to cheat the compiler and throw it without it being checked. If you do you that you may get an UndeclaredThrowableException , except in other cases, where it could throw up as an UnexpectedException , or an UnknownException (which is unrelated to UnknownError , which is only for "serious exceptions"), or an ExecutionException , or an InvocationTargetException , or an ExceptionInInitializerError .

Oh, and we mustn't forget Java 8's snazzy new UncheckedIOException , which is a RuntimeException exception designed to let you throw the exception checking concept out the window by wrapping checked IOException exceptions caused by I/O errors (which don't cause IOError exceptions, although that exists too) that are exceptionally difficult to handle and so you need them to not be checked.

Thanks Java!

I've read a lot about exception handling, even if (most of the time) I cannot really say I'm happy or sad about the existence of checked exceptions this is my take : checked exceptions in low-level code(IO, networking, OS, etc) and unchecked exceptions in high-level APIs/application level.

Even if there is not so easy to draw a line between them, I find that it is really annoying/difficult to integrate several APIs/libraries under the same roof without wrapping all the time lots of checked exceptions but on the other hand, sometime it is useful/better to be forced to catch some exception and provide a different one which makes more sense in the current context.

The project I'm working on takes lots of libraries and integrates them under the same API, API which is completely based on unchecked exceptions.This frameworks provides a high-level API which in the beginning was full of checked exceptions and had only several unchecked exceptions(Initialization Exception, ConfigurationException, etc) and I must say was not very friendly . Most of the time you had to catch or re-throw exceptions which you don't know how to handle, or you don't even care(not to be confused with you should ignore exceptions), especially on the client side where a single click could throw 10 possible (checked) exceptions.

The current version(3rd one) uses only unchecked exceptions, and it has a global exception handler which is responsible to handle anything uncaught. The API provides a way to register exception handlers, which will decide if an exception is considered an error(most of the time this is the case) which means log & notify somebody, or it can mean something else – like this exception, AbortException, which means break the current execution thread and don't log any error 'cause it is desired not to. Of course, in order to work out all custom thread must handle the run() method with a try {…} catch(all).

public void run(){

 try { ... do something ... } catch (Throwable throwable) { ApplicationContext.getExceptionService().handleException("Handle this exception", throwable); } 

}

This is not necessary if you use the WorkerService to schedule jobs(Runnable, Callable, Worker), which handles everything for you.

Of course this is just my opinion, and it might not be the right one, but it looks like a good approach to me. I will see after I will release the project if what I think it is good for me, it is good for others too… 🙂