
1.异常的介绍
1.1 异常的概念
在Java中,将程序执行过程中 发生的不正常行为 称为异常。

java中不同类型的异常 ,都有与其对应的类来进行描述。

1.2 异常的体系结构

1.3 异常的分类




2.异常的处理

异常处理的核心思想 就是 EAFP
EAFP: 先操作,遇到问题再处理,事后认错型。"It's Easier to Ask Forgiveness than Permission" 事后获取原谅比事前获取许可更容易
优势:正常 流程和错误 流程是分离开的, 程序员更关注正常流程,代码更清晰,容易理解代码。
在Java中,异常处理主要的5个关键字 :throw、try、catch、final、throws。
2.1 抛出--throw 与 捕获--try-catch
在编写程序时,如果程序中出现错误 ,此时就需要将错误的信息告知给调用者,比如:参数检测。
在Java中,可以借助 throw 关键字,抛出一个指定的异常对象,将错误信息告知给调用者。具体语法如下:


异常的捕获 ,也就是异常的具体处理方式 ,主要有两种 :异常声明 throws 以及try-catch捕获处理。
处在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想 处理该异常,此时就可以借助 throws 将异常抛给方法的调用者 来处理。即当前方法不处理异常,提醒方法的调用者处理异常。

throws 对异常并没有真正处理 ,而是将异常报告给抛出异常方法的调用者 ,由调用者 处理。如果真正要对异常进行处理,就需要try-catch。





注意事项
(1)try块内 抛出异常位置之后的代码将不会被执行
(2)如果抛出异常类型 与 catch 时异常类型不匹配 ,即异常不会被成功捕获 ,也就不会被处理 ,继续往外抛(方法的调用者 ),直到 JVM 收到后中断程序----异常是按照类型来捕获的。

(3)try中可能会抛出多个 不同的异常 对象,则可以用多个 catch 来捕获 ----即多种异常,多次捕获(try-catch尽量一一对应)。
(4)如果多个异常 的处理方式是完全相同, 也可以合并到同一个 catch 中。

(5)如果异常 之间具有父子 关系,catch中一定是子类异常在前 ,父类异常在后,否则语法错误。
(6)可以通过一个 catch 捕获所有的异常 ,即多个异常,一次捕获(不推荐)。

由于 Exception 类 是所有异常类的父类, 因此可以用这个类型表示捕捉所有异常。

2.2 finally
在写程序时,有些特定的代码,不论程序是否发生异常,都需要执行 ,比如程序中打开的资源:网络连接、数据库 连接、IO流 等,在程序正常或者异常退出时,必须要对资源进进行回收 。另外,因为异常会引发程序的跳转,可能导致有些语句执行不到,finally就是用来解决这个问题的。

问题:既然 finally 和 try-catch-finally 后的代码都会执行,那为什么还要有finally呢?
对于某些程序(代码),如果正常输入,成功接收输入后程序就返回了,try-catch-finally之后的代码根本就没有执行 ,即输入流就没有被释放,造成资源泄漏。

注意:finally 中的代码一定会执行的,一般在 finally 中进行一些资源清理的扫尾工作。
finally 执行的时机是在方法返回之前 (try 或者 catch 中如果有return, 会在这个 return 之前执行 finally)
但是如果 finally 中也存在 return 语句, 那么就会执行 finally 中的 return , 从而不会执行到try 中原有的 return。
一般我们不建议在 finally 中写 return (被编译器当做一个警告).
2.3 异常处理流程总结

3.自定义异常类


模拟一个登录场景
java
import java.util.Scanner;
class UsernameError extends Exception {
public UsernameError(String message) {
super(message);
}
}
class PasswordError extends Exception {
public PasswordError(String message) {
super(message);
}
}
public class Test {
private static void login() throws UsernameError, PasswordError {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名: ");
String username = scanner.next();
System.out.println("请输入密码: ");
String password = scanner.next();
// 验证用户输入的用户名和密码是否正确.
if (!username.equals("admin")) {
throw new UsernameError("用户名错误");
}
if (!password.equals("123456")) {
throw new PasswordError("密码错误");
}
System.out.println("登录成功");
}
public static void main(String[] args) throws PasswordError, UsernameError {
// 模拟一个登录的场景
login();
}
}


