02-Exception和Error的区别

2.1 Exception和Error的区别

Exception和Error都是Throwable的子类。

Error一般是致命异常,会导致程序(或JVM)处于非正常、不可恢复的状态。针对此类错误,一般也不需要捕获,程序无法处理,只能人工介入。比如OutOfMemoryError、StackOverFlowError等。

Exception是非致命异常,序本身可以处理,可以通过catch来进行捕获。Exception 又可以分为 受检查异常(必须处理) 和 不受检查异常(可以不处理)。

在这里插入图片描述

NoClassDefFoundError和ClassNotFoundException的区别:

ClassNotFoundException is an exception that occurs when you try to load a class at run time using Class.forName() or loadClass() methods and mentioned classes are not found in the classpath.
这是一个运行时异常,比如当你想连接数据库,却没有更新相应jar包的classpath。

NoClassDefFoundError is an error that occurs when a particular class is present at compile time, but was missing at run time.
例如,某个class在编译时有,但是不小心删除了,运行时找不到。

2.2 运行时异常和一般异常的区别

受检查异常(一般异常)

受检查异常(一般异常)需要在代码中显示进行捕获,否则编译会出错。如果能自行处理则可以在当前方法中捕获异常,如果无法处理,则继续向调用方抛出异常对象。
受检查异常又分为:无能为力、引起注意型和力所能及、坦然处置型。比如字段超长引起的SQLException,即使重复再多次也会异常,处理办法是完整保留异常现场,等待工程师介入;如未授权异常(UnAuthorizedException),则可以跳转到权限申请页面。

非受检查异常(运行时异常)

非受检查异常都继承自RunTimeException,不需要程序进行显示捕获和处理。一般分为:

  1. 可预测异常:比如IndexOutOtBoundsException、NullPointerException,提前做好边界检测和空指针检测。不必要进行显示捕获以免影响可读性和性能。
  2. 需捕获异常:比如Duboo的远程服务超时异常DubboTimeoutException,不能因为服务端异常导致客户端不能用,可以尝试重试或降级处理。
  3. 可忽略异常:指框架或系统产生的且会自行处理的异常,而程序无须关心。比如Spring的NoSuchRequestHandlingMethodException异常,程序会自动跳转404页面。

为了加深理解,下面我们结合出国旅行的例子说明一下异常分类。
第一,机场地震,属于不可抗力,对应异常分类中的Error。在制订出行计划时,根本不需要把这个部分的异常考虑进去。
第二,堵车属于checked 异常,应对这种异常,我们可以提前出发,或者改签机票。而飞机延误异常,虽然也需要check,但我们无能为力,只能持续关注航班动态。
第三,没有带护照,明显属于可提前预测的异常,只要出发前检查即可避免。去机场路上车子抛锚,这个异常是突发的,虽然难以预料,但是必须处理,属于需要捕捉的异常,可以通过更换交通工具应对。检票机器故障则属于可忽略异常,交由航空公司处理,我们无须关心。
——《码出高效》

2.3 try-catch-finally

在代码中通过try-catch 来发现异常,但是有些程序员往往将大段代码定义在一个catch块内,这样非常不利于定位问题,是一种不负责任的做法。
捕获异常时需要分清稳定代码和非稳定代码,稳定代码指的是无论如何都不会出错的代码,例如int a = 0。异常捕获是针对非稳定代码的,捕获时要区分异常类型并做相应的处理。

如果异常在当前方法的处理能力范围之内且没有必要对外透出,那么就直接捕获异常并做相应处理;否则向上抛出,由上层方法或者框架来处理。无论采用哪种方式处理异常,都严禁捕获异常后什么都不做或打印1行日志了事。如果在方法内部处理异常,需要根据不同的业务场景进行定制处理,如重试、回滚等操作。如果向上抛出异常,需要在异常对象中添加上下文参数、局部变量、运行环境等信息,这样有利于排查问题。

finally代码块的职责不在于对变量进行赋值等操作,而是清理资源、释放连接、关闭管道流等操作,此时如果有异常也要做try-catch。
不要在finally代码块执行return语句。

2.4 try-with-resources

try-catch-finally结构代码:

    Scanner scanner = null;
        try {
            scanner = new Scanner(new File("D://read.txt"));
            while (scanner.hasNext()) {
                System.out.println(scanner.nextLine());
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (scanner != null) {
                scanner.close();
            }
        }

如果try部分和finally部分同时抛出异常,则finally部分异常会最终抛出,而try部分异常会被抑制。

JAVA7之后引入try-with-resources:

try (Scanner scanner = new Scanner(new File("test.txt"))) {
    while (scanner.hasNext()) {
        System.out.println(scanner.nextLine());
    }
} catch (FileNotFoundException fnfe) {
    fnfe.printStackTrace();
}

若同时出现异常,则抛出try部分异常。

JAVA9之后,如果你已经有一个资源是 final 或等效于 final 变量,您可以在 try-with-resources 语句中使用该变量,而无需在 try-with-resources 语句中声明一个新变量。

面对必须要关闭的资源,我们总是应该优先使用 try-with-resources 而不是try-finally。随之产生的代码更简短,更清晰,产生的异常对我们也更有用。try-with-resources语句让我们更容易编写必须要关闭的资源的代码,若采用try-finally则几乎做不到这点。
——《Effective JAVA》

任何实现 java.lang.AutoCloseable或者 java.io.Closeable 的对象,如InputStream、OutputStream 、Scanner 、PrintWriter都可以使用try-with-resources

2.5 异步编程的异常捕获

参考Promise,JAVA8引入的CompletableFuture。
待补充…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值