1. 什么是异常

异常指程序运行中出现的不期而至的各种状况,如:文件找不到、网络连接失败、非法参数等,它影响了正常的程序执行流程。

异常类型:

  • 检查性异常

    最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。

  • 运行时异常

    运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。

  • 错误
    错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。

异常体系结构:

所有的异常类是从 java.lang.Exception 类继承的子类。

Exception 类是 Throwable 类的子类。除了 Exception 类外,Throwable 还有一个子类 Error。

  • Error

    • Error 类对象由 JVM 生成并抛出,大多数错误与代码编写者所执行的操作无关。
    • 错误一般发生在严重故障时,它们在 Java 程序处理的范畴之外。
  • Exception
    在 Exception 分支中有一个重要的子类 RuntimeException(运行时异常),这类异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。

Error 和 Exception 的区别:

  • Error 通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,JVM 一般会选择终止线程;

  • Exception 通常情况下是可以被程序处理的,并且在程序中应该尽可能的去外理这些呈常。

2. 异常处理机制

捕获异常

使用 trycatch 关键字可以捕获异常。

try/catch 代码块放在异常可能发生的地方。try/catch 代码块中的代码称为保护代码。

使用 try/catch 的语法如下:

1
2
3
4
5
6
7
try {
// 代码
} catch (ExceptionName e) {
// 代码
} catch (ExceptionName e) { // 可以在 try 语句后面添加任意数量的 catch 块
// 代码
}

finally 关键字用来创建在 try 代码块后面执行的代码块。

  • 无论是否发生异常,finally 代码块中的代码总会被执行。

  • 在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。

finally 代码块出现在 catch 代码块最后,语法如下:

1
2
3
4
5
6
7
8
9
try {
// 代码
} catch (ExceptionName e) {
// 代码
} catch (ExceptionName e) {
// 代码
} finally {
// 代码
}

不要在 finally 块中使用 return

原因:try 块中的 return 语句执行成功后,并不马上返回,而是继续执行 finally 块中的语句,如果此处存在 return 语句,则会在此直接返回,无情丢弃掉 try 块中的返回点。

注意事项:

  • catch 不能独立于 try 存在
  • 在 try/catch 后面添加 finally 块并非强制性要求
  • try 代码后不能既没 catch 块也没 finally 块
  • try, catch, finally 块之间不能添加任何代码

抛出异常

在 Java 中, throwthrows 关键字是用于处理异常的。

  • throw 关键字用于在代码中抛出异常
  • throws 关键字用于在方法声明中指定可能会抛出的异常类型

3. 自定义异常

使用 Java 内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。

一个异常类和其它任何类一样,包含有变量和方法。

在程序中使用自定义异常类,大体可分为以下几个步骤:

  1. 创建自定义异常类
  2. 在方法中通过 throw 关键字抛出异常对象
  3. 如果在当前抛出异常的方法中处理异常,可以使用 try/catch 语句捕获并处理;否则在方法的声明处通过 throws 关键字指明要抛出给方法调用者的异常,继续进行下一步操作
  4. 在出现异常方法的调用者中捕获并处理异常

注意事项:

  • 所有异常都必须是 Throwable 的子类
  • 如果希望写一个检查性异常类,则需要继承 Exception 类
  • 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。