Back to
top
Java异常深入浅出 - 杨挺的博客 | Tommy's Blog

Java异常深入浅出

"Java异常深入浅出"

Posted by Tommy on March 28, 2021

异常介绍

异常就是有异于常态,和正常情况不一样,有错误出现。在java中,阻止当前方法或作用域的情况,称之为异常。

异常分类

异常分类图

Exception具体实现

在系统开发中,平时经常需要使用的两种异常,一种是需要检查(checked)的,一种是不需要检查(unchecked)的。 那为什么需要两种异常呢?

  • 用来区分告警的优先级。系统异常优先级高,因为说明系统服务、代码存在问题。
    • 业务异常,是已知的,因为其他客观因素导致的,比如用户输入的身份证格式有问题、用户购买商品时金额不足等。
    • 系统异常,是未知的,不知道啥时候会发生,如果发生了说明系统本身或者系统上下游存在问题,需要立马告警出来,让相关开发者感知到;以便发现问题和后续优化问题。比如:系统上下游服务抖动、请求超时、请求参数存在问题等。
  • 使代码更清洁,该处理(checked)的异常内部处理掉,无法处理(unchecked)的异常告警出来。

往往对于开发者来说,比较难区分,何为系统系统,何为业务异常。其中系统异常是unchecked的,业务异常是checked。

RuntimeException

RuntimeException是在Java虚拟机的正常操作期间可以抛出的那些异常的超类,是Exception的子类,是Exception中unchecked子类的超类。 比如系统上下游抖动、请求超时等,是允许在系统运行期间抛出的,所以该类异常应该继承自RuntimeException;且无需检查(unchecked)。 所以系统异常应该继承自RuntimeException

开发时具体实现:


/**
 * @Author : TommyYang
 * @Time : 2021-03-27 12:40
 * @Software: IntelliJ IDEA
 * @File : SystemException.java
 */
public class SystemException extends RuntimeException {

    private String code;

    public SystemException(String code) {
        this.code = code;
    }

    public SystemException(String message, String code) {
        super(message);
        this.code = code;
    }

    @Override
    public String toString() {
        return "SystemException{" +
                "code='" + code + '\'' +
                '}';
    }

}

Exception

异常类和任何不是RuntimeException的子类的子类都是检查异常。 检查的异常需要在方法或构造函数的throws子句中声明,如果它们可以通过执行方法或构造函数抛出,并在方法或构造函数边界之外传播。 比如用户输入的身份证格式有问题、用户购买商品时金额不足等,这些是在开发系统的时候,就会已经的会出现这样的问题,这类异常是应该内部处理(checked)掉,而不应该告警出来。 所以业务异常应该继承自Exception,且需要检查(checked)。

开发时具体实现:


/**
 * @Author : TommyYang
 * @Time : 2021-03-27 12:40
 * @Software: IntelliJ IDEA
 * @File : BusinessException.java
 */
public class BusinessException extends Exception {

    private String code;

    public BusinessException(String code) {
        this.code = code;
    }

    public BusinessException(String message, String code) {
        super(message);
        this.code = code;
    }

    @Override
    public String toString() {
        return "BusinessException{" +
                "code='" + code + '\'' +
                '}';
    }
}

测试


/**
 * @Author : TommyYang
 * @Time : 2021-03-27 13:19
 * @Software: IntelliJ IDEA
 * @File : ExceptionTest.java
 */
public class ExceptionTest {

    /**
     * 测试checked异常
     */
    @Test
    public void testException()  {
        try {
            throwsBusinessException();
        } catch (BusinessException e) {
            System.out.println("这是一个业务异常,内部处理掉" + e.toString());
        }
    }

    /**
     * 测试unchecked异常
     */
    @Test
    public void testRuntimeException() {
        throwsSystemException();
    }

    /**
     * 抛出业务异常(checked)
     * 所以需要throw出去,让外部调用方感知到,这是一个checked的异常,是已经问题
     */
    private void throwsBusinessException() throws BusinessException {
        throw new BusinessException("403");
    }

    /**
     * 抛出系统异常(unchecked)
     */
    private void throwsSystemException() {
        throw new SystemException("400");
    }

}

Error介绍

Error表示严重的问题,合理的应用程序不应该试图捕获。 大多数这样的错误是异常情况。 ThreadDeath错误虽然是“正常”的条件,但也是Error一个子类,因为大多数应用程序不应该试图抓住它。

Error是由虚拟机生成并抛出,大多数错误与代码开发者所执行的操作无关。 常见的Error,比如Java虚拟机运行错误(VirtualMachineError);当JVM执行操作所需的内存资源不够时,将出现OutOfMemoryError;当这些异常发生时,JVM一般会选择线程终止。 还有部分Error是发生在虚拟机试图执行应用时,比如类定义错误(NoClassDefFoundError)、链接错误(LinkageError);这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。 对于合理设计的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。 在Java中,错误通常是使用Error的子类描述。