Java 捕获异常-为什么有必要?

Java 捕获异常-为什么有必要?,java,exception,exception-handling,try-catch,Java,Exception,Exception Handling,Try Catch,假设我有这段微不足道的代码,运行时列表大小为4 try{ for(int i = 0; i < list.size(); i++){ list.get(10); } }catch(NullPointerException e){ System.out.println(" exception to string :" + e.toString()); System.out.println(" exception get cla

假设我有这段微不足道的代码,运行时列表大小为4

try{
    for(int i = 0; i < list.size(); i++){
        list.get(10);
    }

}catch(NullPointerException e){
        System.out.println(" exception to string :" + e.toString());
        System.out.println(" exception get class" + e.getClass());
        e.printStackTrace();
}
试试看{
对于(int i=0;i
因此JVM将抛出一个索引越界异常,而不必在catch块中实现它

类似地,如果列表为null,JVM将抛出null指针异常


既然如此,为什么还要声明IndexOutOfBoundsException或NullPointerException呢?为什么不在catch块中声明一个泛型异常呢?这种方法的优点和缺点是什么?

通常,您不应该在代码中的某个地方捕获通用异常,因为它通常表示代码中有一个需要修复的bug


某些与外部资源相关的已检查异常(如IOException)不在您的控制范围内,因此您应该捕获它们并对其作出反应,但应通过事先检查对象来避免NullPointerException或IndexOutOfBoundException

您肯定知道,基本上有两种类型的异常:已检查和未检查。您需要声明或捕获已检查的异常,但对于未检查的异常不必这样做

那么有什么区别呢?这通常取决于谁使用它们,但通常是这样的:

  • 对于预期最终会出错的事情,会引发检查异常,例如,
    IOException
    等。文件不可用(不存在、锁定等)或不可写不是永远不会发生的事情,开发人员可以尝试阻止。因为您必须预期这些事情会出错,所以您将使用检查异常来强制方法签名声明这些事情可能会出错,或者捕获异常并处理该情况
  • 未经检查的异常通常用于可以但不应该出错的事情。在许多情况下,这是由于编程错误(如NullPointerException、IndexOutofBoundException等)或意外的系统故障(数据库不可用等)。您通常不会明确地捕捉到它们,因为它们无论如何都是不需要的
也就是说,在某些情况下,选中或未选中的异常被用于其他用途(例如,在库中,需要依赖于能够冒泡出大量异常,从而将选中的异常包装为未选中的异常)

至于签名中的捕获/声明:您通常希望对选中的异常尽可能明确,即,您可能希望以与处理
SQLException
不同的方式处理
IOException
。未经检查的异常可能只是被捕获和报告(例如,通过记录或重新引用它们),但即使在这些情况下,您也可能希望显式捕获一些异常,例如,
EJBException
s,它们是由ejb抛出的,可能只是实际检查异常的包装,因此您可能希望将其打开


关于
NullPointerException
的最后一句话:您可能永远都不想显式捕获它们,因为它们本来就不应该出现(要么确保没有任何内容为null,要么在访问这些内容之前进行检查),而且在一个try块中(直接和在调用的方法中)经常有很多内容可能为null你很难做出合理的反应。在这种情况下,最好只捕获任何未处理的异常(就像线程一样),并将其报告给开发人员,以便他们可以查看并解决问题。

为了理解为什么您可能希望在catch块中使用更具体的异常,而不仅仅是通用的
可丢弃的
(这意味着所有可能出错的事情),你可能想考虑这里发生了什么。

在创建将在生产环境中运行多年的软件时,您需要它非常、非常健壮。这意味着您希望您的代码能够优雅地处理任何情况,并在出现问题时保持运行

在您显示的特定代码中,列表太短(一个偶尔会出现错误的库)是完全可以接受的,但如果
list
为null,则这是一个致命的、不可预见的错误

最简单的区分方法是使用异常层次结构的设计方式,并使用不同的catch块


此外,如果您使用Java 7或更高版本,您可以使用管道符号创建一个组合catch块,该符号允许您保留原始异常,即使处理代码相同。

一些异常实际上可以在代码中修复…例如:在写入套接字时在IOException中运行,您可以启动重新连接序列并重试再一次…你正在给那里的用户发送一条自定义消息。这里你有一个原因