捕获Java中的exception

Java中存在某些预定义的exception,如果抛出这些exception,则会报告发生了严重的事情并且您可以更好地改进代码,而不是在catch块中捕获它们(如果我已正确理解它)。 但是我仍然发现许多程序,其中包含以下内容:

} catch (IOException e) { ... } catch (FileNotFoundException e) { .... } 

我认为IOException和FileNotFoundException正是这种exception,我们不应该在catch块中捕获它们。 为什么人们这样做? 这样抓住他们会更好吗? 无论如何,Java编译器都会警告这种问题。

谢谢。

不,捕获IOExceptionFileNotFoundException没有错 – 如果你能真正处理这些exception。 这是重要的一点 – 你真的可以面对那个例外吗? 有时您可以 – 通常在服务器的顶层,例如,因为一个请求失败并不意味着下一个请求无法继续。 客户端应用程序中的频率较低,但这在很大程度上取决于具体情况。 当您尝试批量导入时无法读取文件? 好的,中止操作但不一定关闭整个过程……

不可否认,你不应该那么FileNotFoundExceptionFileNotFoundException会被它派生的IOException所掩盖。 幸运的是,编译器完全无法阻止你这样做。

您显示的顺序,在FileNotFoundException错误之前捕获了IOException 。 由于FileNotFoundException扩展了IOException ,当抛出FileNotFoundException时,将使用第一个处理程序,第二个处理程序是死代码。

我没有尝试过,但是如果编译的话,我有点惊讶。 我希望像FindBugs这样的静态分析工具会发现这个错误。

至于是否应该捕获FileNotFoundException ,它取决于调用者。 但是,我会说FileNotFoundException通常可以以有意义的方式恢复 – 提示另一个文件,尝试回退位置 – 而不是简单地记录错误或中止进程。

Java中有两种类型的exception,已检查的exception和未经检查的exception。

必须在catch块中处理已检查的exception。 不这样做会导致编译器错误。 IOException是已检查exception的示例,必须进行处理。 你在这里实际做什么取决于有问题的应用程序,但必须处理Exception以保持编译器满意。

不需要捕获未经检查的exception。 从RuntimeException扩展的所有类都是未选中的。 一个很好的例子是NullPointerException或ArrayIndexOutOfBoundsException。 编译器不会强制您捕获这些exception,但它们可能仍会在程序运行时发生,从而导致崩溃。

对于记录,可以抛出IOException,就像尝试打开不存在的文件一样简单。 处理这样的事情并优雅地恢复是一个好主意(对话框告诉用户文件不存在并重新出现打开文件对话框),而不是让程序崩溃。

这样做是为了以不同方式处理不同类型的exception。 通常,您希望首先捕获最细粒度的exception,如果在catch块的开头放置更广泛的exception,则首先执行该代码,然后单击finally块。

Jon是对的,捕获IOException的catch将捕获所有IOExceptions和IOException的任何子类型,并且由于FileNotFoundException是一种IOException,它永远不会遇到第二次捕获。

正如乔恩所说 ,在许多情况下捕捉这些例外都很好。 您不应该捕获的exception类型是NullPointerException和ArrayIndexOutOfBoundsException,它们表示代码中的错误。

Java有两种类型的exception:已检查的exception和未经检查的exception(从RuntimeExceptioninheritance的exception)。

检查的exception(例如IOException)通常用于不可预测的场景,这些场景是编写更好的代码无法避免的。 它们被检查的事实意味着编译器强制您编写代码以解决exception情况的可能性。 例如,您必须考虑FileNotFoundException的可能性,因为您无法保证该文件将存在(有人可能会在您的程序运行时移动它)。 可能会发生IOException,因为网络连接被删除。 编译器强制您提供处理这些情况的策略,即使它只是通过允许exception向上传播以调用代码来处理代码来传递代价。

另一方面,未经检查的exception最适用于通过更改代码可以避免的事情。 如果代码检查空引用的可能性,则始终可以避免NullPointerException。 同样,如果您对索引很谨慎,那么您将永远不会得到ArrayIndexOutOfBoundsException。 编译器不会强迫您处理这些场景,因为它们代表了应该修复的错误。

我认为IOException和FileNotFoundException正是这种exception

不,这些实际上是“其他”类型的例外,超出了你的编程技巧。 无论你编程多好,编译器和库都会使你“意识到”可能发生的事情。

想想这个场景:

您创建一个将数据保存到临时文件夹的应用程序。

一切都没问题,你已经检查了文件夹是否存在,如果没有,你可以自己创建它。

然后你要写2 mb到​​那个临时文件夹。

突然,其他系统进程,删除你的临时文件夹,你不能再写了。

没有什么可以做到以编程方式阻止这种情况,在某些系统中可能会发生操作(在unix中root用户可能会执行rm -rf / tmp而且你无能为力。在windows中我认为系统不会让其他进程删除正在使用的文件)

通过强制您检查代码中的这种exception,平台设计者认为至少您已经意识到这一点。

Jon是正确的,有时候你无能为力,可能在程序死之前记录,被认为是“处理exception”(糟糕的句柄是,但至少处理)

 try { .... } catch( IOException ioe ) { logger.severe( String.format("Got ioe while writting file %s. Data was acquired using id = %d, the message is: %s", fileName, idWhereDataCame, ioe.getMessage()) ); throw ioe; } 

您可以做的另一件事是“链接”exception以适应抽象。

可能你的应用程序有一个GUI,向用户显示IOException并不意味着什么或可能是一个安全漏洞 。 可以发送修改后的消息。

 try { .... } catch( IOException ioe ) { throw new EndUserException("The operation you've requeste could not be completed, please contact your administrator" , ioe ); } 

并且EndUserException可能被困在gui中的某个地方并通过Dialog消息呈现给用户(而不是仅仅在没有进一步信息的情况下消失他眼中的应用程序)。 当然,你无法做任何事情来恢复IOException,但至少你会死于风格:P

最后,客户端代码可以使用不同的实现,并非所有exception都有意义。

例如,再考虑第一种情况。 同样的“操作”可以有三种“插件”服务来执行数据保存。

 a) Write the data to a file. b) Or, write to a db c) Or write to a remote server. 

界面不应抛出:

 java.io.IOException java.sql.SQLException 

也不

 java.net.UnknownHostException 

但相反的是

 my.application.DataNotSavedException 

并且不同的实现将在正确的级别处理exception, 并将其转换为适当的抽象:

客户代码:

  DataSaver saver = DataServer.getSaverFor("someKeyIdString"); try { saver.save( myData ); } catch( DataNotSavedException dnse ) { // Oh well... . ShowEndUserError("Data could not be saved due to : " dnse.getMessage() ); } 

实施代码:

  class ServerSaver implements DataSaver { .... public void save( Data data ) throws DataNotSavedException { // Connect the remore server. try { Socket socket = new Socket( this.remoteServer, this.remotePort ); OuputStream out = socket.getOut.... .... .... } catch ( UnknownHostException uhe ) { // Oops.... throw new DataNotSavedException( uhe ); } } } 

FileSaver和DatabaseSaver会做类似的事情。

所有这些都是Checked Exceptions,因为编译器会让你检查它们。

何时使用其中一个(选中/未选中): 此处

还有其他两种: 这里

最后对运行时更简单的解释是: 这里

把这个想法放在一边:可能在另一个领域它更清楚

如果前面的车突然停了,你会怎么做

停止!

所以我们处理exception。

所以回到代码:

如果您需要的文件不可用,您会怎么做?

  1. 有备份。 作为资源编译,因为它是您的程序的一部分。 我不是在开玩笑。
  2. IFF这是用户提供的文件:告诉用户; 这是他们的档案。
  3. 由于您的软件系统已损坏,因此中止程序并向用户发送消息。

我认为没有第四种选择。

我们的C#/ VC ++兄弟选择未经检查的exception。 许多“专家”认为已检查的例外是不好的:我的论点是生活很艰难,克服困难。 检查的exception代表已知的故障模式:必须解决。 您的鱼骨图对于正常操作具有直接的谎言,并且为了失败而从侧面分支。 已检查的exception是预期的故障。

现在,一旦开始处理运行时exception,它就会变得有趣。 Java程序通常可以使用不起作用的函数正常运行。 通过这个,我的意思是他们抛出空指针exception,数组边界错误,无效参数,并用尽堆空间。 这使得增量交付非常可行。

(如果您遇到捕获运行时错误,请记录它们。否则您永远不知道要解决问题)