java 异常总结

Java中异常处理是识别及响应错误的机制。有效地异常处理能使程序更加健壮。异常处理是非功能性需求。

一、异常的处理机制

Java 通过面向对象的方法进行异常处理。每个异常都是一个对象。

第一步、当程序违反语义规则时,自动生成一个异常类对象。两种情况会生成异常类对象。一种是内置的语义检查。另一种是自定义的异常,用throw关键字触发异常。
第二步、生成的异常对象将被提交给运行时系统,此过程为抛出(throw)异常。
第三步、当运行时系统接收到异常对象时,会寻找能处理此异常的代码并交给其处理,此过程为捕获(catch)异常。
第四步、如果运行时系统找不到可以捕获异常的方法,则将终止系统,结束程序。

二、异常类的层次结构

Java定义了一个异常类的层次结构,以java.lang.Throwable开始,扩展出Error和Exception,Exception又扩展出RuntimeException。

RuntimeException表示的是代码所导致的问题,如数组访问越界,空指针异常,类转换异常等。而派生自Exception类的异常所表示的并不是代码本身的问题所导致的非正常状态,而是应用本身无法控制的情况。例如一个应用在尝试打开一个文件并写入的时候,该文件已经被另外一个应用打开从而无法写入。
Error是很难通过程序解决的问题。这些问题基本上是无法恢复的,例如内存、堆栈空间不足等。一般情况下,不会对从Error类派生的异常进行处理。

系统异常和普通异常的解决方案:
普通异常必须被try..catch处理或用throws声明抛给上层调用方法,所以普通异常也称为checked异常。
系统异常可以处理也可以不处理,所以,编译器不强制用try..catch处理或用throws声明,所以系统异常也称为unchecked异常。

三、关键字try,catch,throw,throws,finally

try指定一块需要预防异常的程序。catch子句指定捕捉的异常类型。 throw语句抛出异常。 throws标明方法可能抛出的异常。finally是确保不管发生什么异常都被执行的语句。
每当遇到一个try语句,"异常"的框架就放到堆栈上面,直到所有的try语句都完成。如果下一级的try语句没有对某种"异常"进行处理,堆栈就会展开,直到遇到有处理这种"异常"的try语句。

在JDK7中提供了try-with-resources机制, 它规定你操作的类只要是实现了AutoCloseable接口就可以在try语句块退出的时候自动调用close 方法关闭流资源。

四、处理异常

三种处理异常的基本模式:转换(translate)、重试(retry)和恢复(recover)。
转换经常用于处理受检异常(checked exception),在方法中异常无法抛出,并且无法恢复时使用。 在这种情况下,将其转换为运行时异常(runtime exception)后抛出是最合适的做法。接下来,运行时异常通常由框架处理。
在处理不可靠的服务时,重试非常有用,前提是重新尝试有意义。一个很好的例子就是网络中断重试。如果定义了这种策略,那么就能够恢复到正常状态。例如,如果通过网络发送数据失败,可以将数据写入本地存储。此外,上面提到的模式可以组合。

// 转换
try {
    throw new IOException("Made up");
} catch (IOException e) {
    throw new RuntimeException(e);
}
// 重试 5次后放弃
boolean end = false;
int count = 0;
while (end == false) {
    try {
        // 发送信息
        if (true) {
            throw new MessagingException("Made up");
        }
        end = true;
    } catch (MessagingException e) {
        if (count >= 5) {
            // 尝试5次放弃。
            throw new RuntimeException("was not able to send message even after five tries", e);
        }
        ++count;
        try {
            Thread.sleep(30000);
        } catch (InterruptedException e1) {
            Thread.currentThread().interrupt();
            throw new RuntimeException(e1);
        }
    }
}
// 恢复:如果传输失败记录到文件
try {
    // 发送信息
    throw new MessagingException("Made up");
} catch (MessagingException e) {
    try {
        // 写文件
        throw new IOException("Made up");
    } catch (IOException e1) {
        // 如果写文件失败,不再进行恢复
        throw new RuntimeException(e1);
    }
}

五、异常处理的建议

1 为可恢复的错误使用受检异常,为编程错误使用非受检异常。

受检异常保证你会针对错误情况提供异常处理代码,这是一种从语言层面上强制编写健壮代码的方式,但引入异常处理代码会导致代码可读性变差。当然,如果有可替代方式或恢复策略的话,捕获异常并做处理看起来似乎也合情合理。

例如,在批量处理任务中,如果是处理子任务时出现问题,那么只记录子任务的异常,继续处理其他的子任务。对失败的任务进行重试或者记录到日志中。

2 避免过度使用受检异常

在方法重写或接口实现中,受检异常会污染其他方法。特别是在API方法中,要慎用。

3 将受检异常转为运行时异常

这是在Spring类的框架中用来减少使用受检异常的方式之一。这样可以将特定的异常限制在特定的模块中,比如把 SQLException 抛到 DAO 层,把有意义的运行时异常抛到客户端层。

4 在 finally 程序块中关闭或者释放资源

这是 Java 编程中广为人知的最佳实践和事实上的标准,尤其是在处理网络和 IO 操作的时候。从 Java7 开始,新增加了一项功能:自动资源管理,或者称之为ARM块。尽管如此,仍然要记住在 finally 块中关闭资源。

5 避免空的 catch 块

空的 catch 块不仅隐藏了错误和异常,同时可能导致对象处于不可用状态或者脏状态。

6 提早抛出(迅速失败)

在导致错误的原始地方就抛出异常。一般是入参错误,导致其他地方抛出异常,这时应该先检查入参,如果有问题即刻抛出异常。

7 延迟处理(throw和throws)

在有能力处理的地方,才能抛出异常。

8 日志要记录完整异常上下文

在程序执行期间,用日志记录错误依然是最好的方法。日志需要记录详细入参。何时何处为何。

在API中,受检异常的使用
首先,Checked Exception应当只在异常情况对于API以及API的使用者都无法避免的情况下被使用。例如在打开一个文件的时候,API以及API的使用者都没有办法保证该文件一定存在。反过来,在通过索引访问数据的时候,如果API的使用者对参数index传入的是-1,那么这就是一个代码上的错误,是完全可以避免的。因此对于index参数值不对的情况,我们应该使用Unchecked Exception。
其次,Checked Exception不应该被广泛调用的API所抛出。
再次,Checked Exception应该有明确的意义。

对于API的用户而言,一旦遇到API抛出Checked Exception,那么就需要考虑使用一个Wrapped Exception来将该Checked Exception包装起来。

参考

java的常见异常与错误总结

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 在使用Java编写应用的时候,我们常常需要通过第三方类库来帮助我们完成所需要的功能。有时候这些类库所提供的很多AP...
    小宇java阅读 3,043评论 0 0
  • 在使用Java编写应用的时候,我们常常需要通过第三方类库来帮助我们完成所需要的功能。有时候这些类库所提供的很多AP...
    小宇java阅读 1,130评论 0 0
  • 异常分类 Java将异常分为两种,Checked异常和Runtime异常。Java认为Checked异常都是可以在...
    LLorenzo阅读 4,155评论 0 1
  • 一、为什么要写 startActivityForResult() 在实际项目中我们会有这样的应用场景,在 Acti...
    珞神阅读 4,831评论 0 0
  • 我最喜欢的音乐,说来太多了,国内的音乐里,之前喜欢萧和古琴,偏于哀怨,现在越来越喜欢古筝和琵琶曲,国外的音乐中最喜...
    Jessy自由行走的猫阅读 3,290评论 0 1

友情链接更多精彩内容