我要投搞

标签云

收藏小站

爱尚经典语录、名言、句子、散文、日志、唯美图片

当前位置:金算盘心水论坛 > 抛出异常 >

Java实用技巧:当不能抛出checked异常时

归档日期:06-06       文本归类:抛出异常      文章编辑:爱尚语录

  checked异常的一个问题是,有时候不允许抛出这样的异常。特别是,如果要覆盖超类中声明的方法,或者实现接口中声明的方法,而那个方法没有声明任何checked异常,那么新的实现也不能声明checked异常。

  因此必须预先处理异常,另外,可以将异常转换为运行时异常,或者绕过它而不处理它。但是,应该这样做吗,这其中是否隐藏着错误?

  checked异常的一个问题是,有时候不允许抛出这样的异常。特别是,如果要覆盖超类中声明的方法,或者实现接口中声明的方法,而那个方法没有声明任何checked异常,那么新的实现也不能声明checked异常。

  因此必须预先处理异常,另外,可以将异常转换为运行时异常,或者绕过它而不处理它。但是,应该这样做吗,这其中是否隐藏着错误?

  只要看一个例子,问题就清楚了。假设有一个File对象的List,需要按它们的标准路径以字典顺序排序。所谓标准路径,是指在解析别名、符号链接和/../及/./之后得到的完整绝对路径。本地方法使用一个比较器,如清单1所示:

  不幸的是,该代码不能通过编译。问题在于,getCanonicalPath()方法抛出一个IOException,因为它需要访问文件系统。通常,当使用checked异常时,可以使用以下两种方法之一:

  通常,至于选择何种方法,取决于是否能在抛出异常时合理地处理异常。如果能,那么使用try-catch块。如果不能,那么声明包装方法本身抛出异常。不幸的是,这两种技巧对于本例都不管用。在compare()方法中无法合理地处理IOException。从技术上讲,似乎可以做到-即返回0、1或-1,如清单2所示:

  然而,这违反了compare()方法的约定,因为它不是一个稳定的结果。对于相同的对象,前后两次调用可能产生不同的结果。如果使用这个比较器来排序,那么意味着最终列表没有被正确排序。所以现在试试第2个选项-声明compare()抛出IOException:

  这也不能通过编译。因为checked异常是方法签名的一部分,在覆盖方法时,不能增加checked异常,就像不能改变return类型一样。那么最后还剩下一个折中选项:在compare()中捕捉异常,将它转换成运行时异常,然后抛出运行时异常,如清单3所示:

  不幸的是,虽然这样可以通过编译,但是这种方法也不管用,其原因较为微妙。Comparator接口定义一个合约(请参阅参考资料)。这个合约不允许该方法抛出运行时异常(防止因违反泛型类型安全而成为调用代码中的bug)。使用这个比较器的方法合理地依靠它来比较两个文件,而不抛出任何异常。它们没有准备好处理compare()中意外出现的异常。

  正是由于这个微妙的原因,让运行时异常成为代码要处理的外部状况是一个坏主意。这样只是逃避问题,并没有真正处理问题。不处理异常所带来的不良后果仍然存在,包括毁坏数据和得到不正确的结果。

  这样便陷入了困境。既不能在compare()内真正有效地处理异常,又不能在compare()之外处理异常。还剩下什么地方可以处理异常-System.exit()?惟一正确的办法是完全避免这种困境。幸运的是,至少有两种方法可以做到这一点。

  有一个File对象的List,需要按它们的标准路径以字典顺序排序。所谓标准路径,是指在解析别名、符号链接和/../及/./之后得到的完整绝对路径。本地方法使用一个比较器,如清单1所示:

  不幸的是,该代码不能通过编译。问题在于,getCanonicalPath()方法抛出一个IOException,因为它需要访问文件系统。通常,当使用checked异常时,可以使用以下两种方法之一:

  通常,至于选择何种方法,取决于是否能在抛出异常时合理地处理异常。如果能,那么使用try-catch块。如果不能,那么声明包装方法本身抛出异常。不幸的是,这两种技巧对于本例都不管用。在compare()方法中无法合理地处理IOException。从技术上讲,似乎可以做到-即返回0、1或-1,如清单2所示:

  然而,这违反了compare()方法的约定,因为它不是一个稳定的结果。对于相同的对象,前后两次调用可能产生不同的结果。如果使用这个比较器来排序,那么意味着最终列表没有被正确排序。所以现在试试第2个选项-声明compare()抛出IOException:

  这也不能通过编译。因为checked异常是方法签名的一部分,在覆盖方法时,不能增加checked异常,就像不能改变return类型一样。那么最后还剩下一个折中选项:在compare()中捕捉异常,将它转换成运行时异常,然后抛出运行时异常,如清单3所示:

  不幸的是,虽然这样可以通过编译,但是这种方法也不管用,其原因较为微妙。Comparator接口定义一个合约(请参阅参考资料)。这个合约不允许该方法抛出运行时异常(防止因违反泛型类型安全而成为调用代码中的bug)。使用这个比较器的方法合理地依靠它来比较两个文件,而不抛出任何异常。它们没有准备好处理compare()中意外出现的异常。

  正是由于这个微妙的原因,让运行时异常成为代码要处理的外部状况是一个坏主意。这样只是逃避问题,并没有真正处理问题。不处理异常所带来的不良后果仍然存在,包括毁坏数据和得到不正确的结果。

本文链接:http://izytravel.com/paochuyichang/208.html