专栏首页暴走大数据Java 的 Checked 和 Unchecked Exception

Java 的 Checked 和 Unchecked Exception

本文作者:王蒙(Matt) http://matt33.com/2016/12/13/java-exception/

如果在 Java 应用中对 Exception 能够正确处理,那么将会使你的程序更具有健壮性。但是很多人对 Exception 中的 Checked ExceptionUnchecked Exception 并不理解,并且 Exception 又常常被被分为 JVM Exception 和程序 Exception,这就让一些开发者显得更加困惑了,本文就这几个概念详细讲述一下。

Checked Exception

Checked Exception 是必须在代码中进行恰当处理的 Exception,而且编译器会强制开发者对其进行处理,否则编译会不通过。你可以使用 catch 语句捕获这些 Exception 或者在方法声明处使用 throws 语句抛出该异常。

一般来说,Checked Exception 的发生主要是由于一些特殊情况没有考虑到,比如如果网络连接失败会抛出 IOException,但是我们的程序应该能够提前预料到这些可能发生的异常,并对其进行处理,这样程序在运行过程中才不会崩掉,这也是编译器强制开发者对 Checked Exception 进行处理的原因。假设在文件传输的过程中网络出现中断,这时候程序应该能够捕获到这种异常并进行处理(重新尝试传输文件)。

Unchecked Exception

Unchecked Exception 的发生有一些是由于开发者代码逻辑错误造成的,比如:NullPointerException 这种异常可以通过检查一个引用是否为 null 来进行避免。

但是也有一些 Unchecked Exception 出现并不是因为开发者程序的问题,这些 Exception 是 java.lang.Error 的子类。就像 OutOfMemoryError 可能发生在任意一个示例对象创建时,但我们不可能在每个对象实例创建时都使用 catch 块去捕获异常。因此,我们也就不可能预料这些异常的发生,编译器在编译时也无法检测到这些异常。

例子

下面这个例子,由于没有对 Checked Exception 进行处理而导致编译失败。

class UnhandledException {
    public static void main(String[] args) {
        throw new Exception();
    }
}

为了使上面的代码可以正确编译,我们可以在 try/catch 块中捕获相应的异常或者是使用 throws 在 main 方法声明处抛出异常。

但是如果在 main 方法内部抛出一个 Unchecked Exception,依然可以正常编译,下面的例子就可以正确编译。正如前面所述,Unchecked Exception 在编译期间是无法提前检测,因此,不对其进行处理也不会影响到正常编译。

class UnhandledException {
    public static void main(String[] args) {
        throw new NullPointerException();
    }
}

Exception 类层次结构

java.lang.Throwable 类是一个 Checked Exception,Java 的 API 定义了 Throwable 的两个子类——java.lang.Exceptionjava.lang.Error, Error 类是 Unchecked Exception 类,而 Exception 则是 Checked Exception类。

Exception 类有一个 Unchecked Exception 子类——java.lang.RuntimeException,NullPointerException 和 ClassCastException 都是 RuntimeException 的子类。RuntimeException 和 Error 的所有子类都是 Unchecked Exception,其他的 Exception 则都是 Checked Exception,如下图所示。

如果创建一个自定义的异常类,它是 Checked Exception 还是 Unchecked Exception 则依赖其父类的类型。如果它继承于一个 Unchecked Exception 类,那么它就是一个 Unchecked Exception,反之依然。

在对 Checked Exception 进行 catch 操作时,也需要遵循一定的规则:在 catch 块中捕获的异常,必须在 try 块中有出现这种异常的可能性。

try {
    System.out.println("...");
} catch(java.io.IOException e) {
}

上面的例子就不能成功编译,因为在 try 块中永远都不会抛出 IOException,所以你也不能去捕获这种异常。但是如果你捕获的是一个 Unchecked Exception,那么就不会有这种问题。

Exception 和 Throwable 这两个类有些特殊,虽然它们都是 Checked Exception 类,但你依然可以捕获它们即使在 try 块中没有抛出该异常的可能性,因此,下面的代码的就可以正确编译。

try {
    System.out.println("...");
} catch(Exception ex) {
}

前面所说的规则对于 Exception 和 Throwable 这两个类并不是完全适用,这是因为对 Exception 和 Throwable 这两个类都有 Unchecked Exception 类型的子类,所以编译器允许你捕获它们(编译器认为你是在捕获一个 Unchecked Exception)。要清楚一点,编译器并不会检查 Unchecked Exception,RuntimeException 是 Exception 的子类,Error 是 Throwable的子类, 而 RuntimeException 和 Error 都是 Unchecked Exception 类。因此,上面的代码是可以正确编译的,编译允许这样做的原因就是因为这种方式是可以捕获到 Unchecked Exception 的。

JVM 和程序异常

JVM Exception 是由 JVM 自己抛出的异常,比如:如果调用的方法使用一个 null 引用,然后 JVM 就会抛出 NullPointerException,或者如果在程序中出现10除以0的情况,JVM 会抛出一个 ArithmeticException。这些异常都是自动地由 JVM 抛出。

除了 JVM Exception 外,其他所有的异常都是由程序引起的异常。程序中,我们可以显式地使用 throw语句抛出异常,这里以 NumberFormatException 为例。NumberFormatException 可能被方法 Integer.parseIntFloat.parseFloat 抛出,都是程序中可能出现的异常。在 Integer 类方法 parseInt 的实现中,可以找到如下的声明:

if (s == null) {
      throw new NumberFormatException("null");
}

而 JVM 不会抛出这种类型的异常,这些异常是使用 throw 语句显式地程序中抛出。当然也可以如下所示在程序中抛出 JVM Exception。

if (s == null) {
      throw new NullPointerException("I told you s shouldn't be null");
}

但是一般情况下,JVM Exception 是不会被开发者抛出的(JVM 自己抛出的),所有的 JVM Exception 都是 unchecked,而程序中的异常则可能是 checked 的或者 unchecked 的。

本文分享自微信公众号 - 暴走大数据(zhouqiantanxi)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spark Core源码精读计划15 | 心跳接收器HeartbeatReceiver

    按照SparkContext初始化的顺序,下一个应该是心跳接收器HeartbeatReceiver。由于笔者感染乙流仍然没有痊愈,状态不好,文中若有疏漏,请批评...

    大数据真好玩
  • Spark shuffle读操作

    1. shuffle过程的数据是如何传输过来的,是按文件来传输,还是只传输该reduce对应在文件中的那部分数据?

    大数据真好玩
  • Flink源码解读系列 | 任务提交流程

    Flink在1.10版本对整个作业提交流程有了较大改动,详情请见FLIP-73。本文基于1.10对作业提交的关键流程进行分析,不深究。 入口: 依旧是main函...

    大数据真好玩
  • Java 异常的分类

    Java中异常分为可以通过try捕捉解决的Exception和不可通过代码解决的Error.

    用户2965768
  • 实践:在运维大数据这事上,Apache Kylin比ELK更擅长?

    他居然不假思索,略带调侃的回答我, “背锅” 与 “惊醒”,随即愣了一下,改口说,“发布” 与 “排障”。

    吃草的罗汉
  • 软件测试行业现状2018年度报告

    https://qablog.practitest.com/wp-content/uploads/2018/10/2018state_of_testing_re...

    软测小生
  • 从linux源码看epoll

    在linux的高性能网络编程中,绕不开的就是epoll。和select、poll等系统调用相比,epoll在需要监视大量文件描述符并且其中只有少数活跃的时候,表...

    无毁的湖光-Al
  • Springboot 2-OAuth 2修改登录加密方式

    Springboot2的Security框架用的是5.0的,较之4.0的密码加密方式有了很大的改变.spring security 5中主推的加密方式为BCry...

    算法之名
  • Mitaka:针对开源情报收集任务的浏览器扩展

    今天给大家介绍的是一款针对开源情报收集任务的浏览器扩展,这款扩展名叫Mitaka,希望该工具可以给广大研究人员的OSINT搜索研究提供帮助。

    FB客服
  • CentOS修改IP、DNS、网关

    修改IP,我装的机器是戴尔的(双网卡):vi /etc/sysconfig/network-scripts/ifcfg-eth0

    meteoric

扫码关注云+社区

领取腾讯云代金券