异常处理

一、概述

Throwable接口有两个子类Error(错误) 和 Exception(异常),而Exception之下又分为运行时异常和非运行时异常。

1. 检查异常/运行时异常

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

java 编译器要求你必须处理的异常,如果不处理,程序就不能编译通过。你代码还没运行呢,编译器就会检查你的代码,会不会出现异常,要求你对可能出现的异常必须做出相应的处理。这样设计的目的是为了提醒开发者处理一些场景中必然可能存在的异常情况,如:IOException,

你使用IO操作的时候,编译器要求你必须要对这段代码try...catch,或者throws exception。

除了RuntimeException与其子类,以及错误(Error),其他的都是检查异常。

处理:必须捕获或者抛出

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

java 编译器不要求强制处置的异常,虽然你有可能出现错误,但是我不会在编译的时候检查,没必要,也不可能。当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。eg:空指针、数组下标越界等。

处理:捕获、抛出、不处理

检查异常和非检查异常是从编译的角度去划分的,运行时异常和非运行时异常是从运行时的角度去划分的,其实检查异常和非运行时异常就是一回事。

2. 第三方应用调用

第三方调用异常,不是按照异常的种类去划分的,而是按照业务的设计去划分的。  

如:redis、webservice、ActiveMq、dubbo等的调用,可能会出现失败,从而导致整个系统出现崩溃。一旦第三方出现调用问题,需要手动处理该异常。

3. 业务异常

  如库存超买超卖等。需要手动处理,使用自定义异常处理。

二、使用

1. @SneakyThrows注解

在实际开发中,大部分情况下的异常,我们都是一路往外抛了事(强制处理我也处理不了啊),所以渐渐的java程序员处理Exception的常见手段就是外面包一层RuntimeException,接着往上丢。这种解决思想尤其在Spring中随处可见,参见《Spring in Action》。

Lombok提供了@SneakyThrows注解,就是为了消除这样的模板代码,使用注解后不需要担心Exception的处理。

示例:

/**
 * @author zls
 * @date 2020/4/4
 */
public class SneakyThrowsTest {
    @SneakyThrows(UnsupportedEncodingException.class)
    public String utf8ToString(byte[] bytes) {
        return new String(bytes, "UTF-8");
    }

    @SneakyThrows
    public void run() {
        throw new Throwable();
    }

    /**
     * 以上两个方法经过编译后会变成以下方法
     * @param bytes
     * @return
     */
    /*public String utf8ToString(byte[] bytes) {
        try {
            return new String(bytes, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw Lombok.sneakyThrow(e);
        }
    }

    public void run() {
        try {
            throw new Throwable();
        } catch (Throwable t) {
            throw Lombok.sneakyThrow(t);
        }
    }*/
}
原理:
显然魔法 藏在Lombok.sneakyThrow(t)中。可能大家都会以为这个方法就是new RuntimeException()之类的 ,然而事实并非如此,
阅读代码可以看出整个方法其实最核心的逻辑是throw (T)t;,利用泛型将我们传入的Throwable强转为RuntimeException。
虽然事实上我们不是RuntimeException,但是没关系,因为JVM并不关心这个。泛型最后存储为字节码时并没有泛型的信息,这样写只是为了骗过javac编译器。
源码:
// 源码位于 package lombok.Lombok.java中
public
static RuntimeException sneakyThrow(Throwable t) { if (t == null) throw new NullPointerException("t");
  // 这里的T传入的RuntimeException类型
return Lombok.<RuntimeException>sneakyThrow0(t); } @SuppressWarnings("unchecked") private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T {
   // 利用泛型将我们传入的Throwable强转为 T类型
throw (T)t; }

参考:

java运行时异常和非运行时异常的区别

Lombok注解-@SneakyThrows

Lombok注解-@SneakyThrows

原文地址:https://www.cnblogs.com/shiyun32/p/10849617.html