# 异常介绍

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

## 异常分类

![异常分类图](https://cdn.jsdelivr.net/gh/filess/img6@main/2021/03/27/1616860311636-a2466f2e-6bb2-437e-bd71-b2124af3fd89.png)

## Exception具体实现

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

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

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

### RuntimeException

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

开发时具体实现：

```java
/**
 * @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）。

开发时具体实现：

```java
/**
 * @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 + '\'' +
                '}';
    }
}
```

### 测试

```java
/**
 * @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的子类描述。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tommyyang.gitbook.io/javainterview/javabase/exception.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
