欢迎光临
我们一直在努力

【第六章】Java中的异常

【第六章】Java——异常机制

    • 前言
  • 一、什么是异常
    • 1. 异常的基本概念
    • 2. 异常和语法错误的区别
      • 编译错误
      • 异常
    • 3. 为什么程序需要异常机制
  • 二、生活化理解异常
    • 1. 正常流程和异常流程
    • 2. 异常处理的意义
  • 三、Java 中的异常体系
    • 1. 所有异常和错误的顶层父类:`Throwable`
    • 2. `Error`
    • 3. `Exception`
  • 四、异常的分类
    • 1. 编译时异常
    • 2. 运行时异常
    • 3. 二者区别总结
      • 编译时异常
      • 运行时异常
  • 五、常见运行时异常
    • 1. `NullPointerException`
    • 2. `ArithmeticException`
    • 3. `ArrayIndexOutOfBoundsException`
    • 4. `StringIndexOutOfBoundsException`
    • 5. `ClassCastException`
    • 6. `NumberFormatException`
  • 六、常见编译时异常
    • 1. `IOException`
    • 2. `FileNotFoundException`
    • 3. `SQLException`
    • 4. `ClassNotFoundException`
  • 七、异常出现后程序会怎样
    • 1. 默认情况:程序中断
    • 2. 异常信息一般包括什么
  • 八、`try-catch` 异常捕获机制
    • 1. 基本作用
    • 2. 示例
    • 3. 执行流程
      • 没有异常
      • 有异常
  • 九、多个 `catch`
    • 1. 匹配原则
    • 2. 注意顺序
  • 十、`finally` 语句块
    • 1. 基本作用
    • 2. 典型用途
    • 3. 示例
    • 4. `finally` 一定执行吗
  • 十一、`try-catch-finally` 的完整形式
    • 1. 组合关系
      • 合法形式
      • 非法形式
  • 十二、异常对象常用方法
    • 1. `printStackTrace()`
    • 2. `getMessage()`
    • 3. `toString()`
    • 4. 示例
  • 十三、`throw` 关键字
    • 1. 作用
    • 2. 示例
    • 3. 使用场景
  • 十四、`throws` 关键字
    • 1. 作用
    • 2. 示例
    • 3. `throw` 和 `throws` 的区别
      • `throw`
      • `throws`
  • 十五、方法重写与异常
    • 1. 基本原则
    • 2. 原因
    • 3. 初学阶段怎么记
  • 十六、自定义异常
    • 1. 为什么要自定义异常
    • 2. 自定义异常的方式
      • 继承 `Exception`
      • 继承 `RuntimeException`
    • 3. 示例:自定义运行时异常
    • 4. 示例:自定义受查异常
  • 十七、`finally` 与 `return` 的关系
    • 1. 先看示例
    • 2. 为什么会这样
    • 3. 更复杂的情况
  • 十八、JDK7 之后的资源自动关闭
    • 1. 优点
    • 2. 前提
  • 十九、异常处理中常见错误
    • 1. 抓了异常却什么也不做
    • 2. 一上来就 `catch(Exception)`
    • 3. 把运行时异常全靠 `try-catch` 掩盖
    • 4. 在 `finally` 中写复杂逻辑
    • 5. 自定义异常时语义不清
  • 二十、什么时候该处理,什么时候该抛出
    • 1. 当前方法能解决,就处理
    • 2. 当前方法解决不了,就往上抛
    • 3. 一般原则
  • 二十一、异常机制和程序健壮性
  • 二十二、学习异常时最容易混淆的几个点
    • 1. `throw` 和 `throws`
    • 2. 编译时异常和运行时异常
    • 3. `final`、`finally`、`finalize`
      • `final`
      • `finally`
      • `finalize`
  • 二十三、学习建议
    • 1. 不要只背概念,要亲手制造异常
    • 2. 多比较“处理前”和“处理后”
    • 3. 重点抓住执行流程
    • 4. 先掌握常见异常,再学自定义异常
  • 二十四、本章知识总结
    • 1. 异常的本质
    • 2. 异常体系
    • 3. 异常分类
    • 4. 异常处理语法
    • 5. 关键区别
    • 6. 开发中的重点
  • 二十五、结语
  • 二十六、附:常见语法速查表
    • 1. `try-catch`
    • 2. `try-catch-finally`
    • 3. `throw`
    • 4. `throws`
    • 5. 自定义异常
    • 6. 自动关闭资源

前言

在编写 Java 程序的过程中,程序并不总是会按照我们的理想情况顺利运行。很多时候,代码在编译阶段看起来没有问题,但在运行阶段却可能因为各种原因出错,例如:

  • 除数不能为 0
  • 数组下标越界
  • 字符串为 null
  • 文件找不到
  • 输入的数据格式不正确
  • 网络连接失败
  • 类型转换失败

这些问题,本质上都属于程序运行过程中的异常情况。 如果程序员对这些异常情况完全不做处理,那么轻则程序报错终止,重则影响整个系统的稳定性和用户体验。

因此,在 Java 里,异常并不是一个“可有可无”的附加知识,而是编写健壮程序必须掌握的内容。一个真正可用的程序,不能只考虑“正常情况下怎么运行”,还必须考虑:

  • 出现错误时怎么办
  • 错误发生后要不要继续执行
  • 如何给调用者一个明确提示
  • 如何避免程序直接崩溃
  • 怎样把错误信息保留下来,方便排查问题

Java 之所以在企业开发中被广泛使用,其中一个重要原因,就是它对异常机制做了比较完整的设计。Java 通过 Throwable 体系,把运行中出现的问题进行了分类,并且提供了:

  • try
  • catch
  • finally
  • throw
  • throws

等一整套处理异常的语法工具。

可以这样理解:

异常机制的作用,不是让程序永远不出错,而是让程序在出错时仍然可控。

本章将围绕 Java 中的异常机制进行系统讲解,尽量从概念、分类、语法、执行流程、常见异常、处理方式、自定义异常、开发规范等多个角度展开说明。 学习这一章时,不能只记住几个关键字,更重要的是要理解异常的本质、传播方式和处理思路。

通过本章学习,可以掌握:

  • 什么是异常
  • 异常与普通错误提示的区别
  • Java 异常体系结构
  • Throwable、Error、Exception 之间的关系
  • 编译时异常和运行时异常的区别
  • try-catch-finally 的基本用法
  • 多个 catch 的匹配顺序
  • finally 的作用
  • throw 和 throws 的区别
  • 如何自定义异常类
  • 常见异常类型及触发场景
  • 异常处理中常见错误与开发建议

一、什么是异常

1. 异常的基本概念

异常,英文叫 Exception。在 Java 中,异常指的是:

程序在运行过程中出现的不正常情况。

这里要特别注意两个词:

  • 运行过程中
  • 不正常情况

也就是说,异常通常不是语法错误,而是程序在执行时遇到了超出预期的问题。

例如:

int a = 10;
int b = 0;
System.out.println(a / b);

这段代码在编译时是可以通过的,因为语法没有问题。 但运行时会报错,因为 0 不能作为除数。

这就是异常。

2. 异常和语法错误的区别

很多初学者容易把“编译错误”和“异常”混在一起。

例如下面这段代码:

int a = "hello";

这不是异常,而是编译错误。 因为代码在编译阶段就已经不合法,程序根本无法运行。

而下面这段:

String str = null;
System.out.println(str.length());

编译没问题,但运行时会出现 NullPointerException。 这才属于异常。

所以可以这样区分:

编译错误

  • 语法、类型、结构不合法
  • 程序连运行机会都没有

异常

  • 编译可以通过
  • 运行时出现问题

3. 为什么程序需要异常机制

如果没有异常机制,程序一旦出错,通常只能:

  • 直接崩溃
  • 没有明确提示
  • 调用者不知道哪里出问题
  • 程序员也难以定位原因

有了异常机制后,可以做到:

  • 捕获错误
  • 给出清晰信息
  • 必要时中断执行
  • 必要时继续执行后续逻辑
  • 统一处理错误情况

因此,异常机制本质上是在帮助程序员管理运行时风险。


二、生活化理解异常

1. 正常流程和异常流程

写程序时,通常都会先考虑一种最理想的情况:

  • 用户输入正确
  • 文件一定存在
  • 网络一定正常
  • 数据格式一定符合要求

这种情况叫正常流程。

但真实世界中常常会有一些意外:

  • 用户输错数据
  • 磁盘文件被删掉了
  • 数据库连接失败
  • 服务器超时
  • 某个对象本来应该有值,但实际上是 null

这些不在正常流程里的情况,就属于异常流程。

2. 异常处理的意义

可以把异常处理理解成:

提前给程序准备“出问题时的备用方案”。

例如:

  • 文件打不开,就提示“文件不存在”
  • 用户输入错误,就提示“请输入合法数字”
  • 网络断开,就提示“连接失败,请稍后重试”

这就是异常机制在程序设计中的现实意义。


三、Java 中的异常体系

1. 所有异常和错误的顶层父类:Throwable

在 Java 中,所有可以被“抛出”的问题对象,最终都继承自 Throwable。

也就是说:

Throwable 是 Java 异常体系的根类。

它下面主要分为两大类:

  • Error
  • Exception

可以简单画成:

Throwable
├── Error
└── Exception

2. Error

Error 表示比较严重的问题,通常不是程序员通过普通代码就能轻易处理的。

例如:

  • StackOverflowError:栈溢出
  • OutOfMemoryError:内存溢出

这些问题通常说明:

  • 程序本身存在严重缺陷
  • 或运行环境资源出现问题

在一般开发中,Error 通常不作为常规异常处理对象。

3. Exception

Exception 才是我们平时编程中最常处理的一类异常。

例如:

  • 数组越界
  • 空指针
  • 文件不存在
  • 类型转换错误
  • 输入输出失败

这些异常大多数都和程序逻辑、输入数据、外部资源有关。


四、异常的分类

在 Java 中,Exception 又可以进一步分成两大类:

  • 编译时异常
  • 运行时异常

1. 编译时异常

编译时异常也叫受查异常,英文常叫:

  • Checked Exception

这类异常的特点是:

编译器要求程序员必须显式处理,否则代码不能通过编译。

例如:

FileInputStream fis = new FileInputStream("a.txt");

这里可能会出现文件找不到的问题,所以编译器会要求你:

  • 要么 try-catch
  • 要么 throws

否则编译报错。

常见编译时异常有:

  • IOException
  • FileNotFoundException
  • SQLException
  • ClassNotFoundException

2. 运行时异常

运行时异常也叫非受查异常,通常是:

  • RuntimeException 及其子类

这类异常的特点是:

编译器不强制要求处理,但运行时可能出问题。

例如:

int[] arr = {1, 2, 3};
System.out.println(arr[5]);

编译器不会阻止你,因为语法合法。 但运行时会抛出:

ArrayIndexOutOfBoundsException

常见运行时异常有:

  • NullPointerException
  • ArithmeticException
  • ArrayIndexOutOfBoundsException
  • ClassCastException
  • NumberFormatException

3. 二者区别总结

编译时异常

  • 编译器强制处理
  • 不处理就无法通过编译
  • 通常和外部资源、环境相关

运行时异常

  • 编译器不强制处理
  • 运行时才会暴露问题
  • 通常和代码逻辑错误有关

五、常见运行时异常

这一部分是学习异常时必须重点掌握的内容,因为这些异常在平时做题和写程序时最常见。

1. NullPointerException

空指针异常。

示例:

String str = null;
System.out.println(str.length());

原因:

  • str 没有真正指向对象
  • 却调用了对象的方法

这是 Java 初学阶段最常见的异常之一。

2. ArithmeticException

算术异常。

示例:

int a = 10;
int b = 0;
System.out.println(a / b);

原因:

  • 整数除以 0

3. ArrayIndexOutOfBoundsException

数组下标越界异常。

示例:

int[] arr = {1, 2, 3};
System.out.println(arr[3]);

原因:

  • 访问了数组有效范围之外的下标

4. StringIndexOutOfBoundsException

字符串下标越界异常。

示例:

String s = "abc";
System.out.println(s.charAt(5));

5. ClassCastException

类型转换异常。

示例:

Object obj = "hello";
Integer num = (Integer) obj;

原因:

  • 实际类型和强制转换目标类型不匹配

6. NumberFormatException

数字格式异常。

示例:

String s = "abc";
int num = Integer.parseInt(s);

原因:

  • 字符串内容不能转换为数字

六、常见编译时异常

1. IOException

输入输出异常,是很多 IO 类操作中常见的父异常类型。

例如:

  • 读文件失败
  • 写文件失败
  • 流关闭失败

2. FileNotFoundException

文件未找到异常。

示例:

import java.io.FileInputStream;

public class Test {
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("abc.txt");
}
}

如果文件不存在,就会出现该异常。

3. SQLException

数据库操作异常。

例如:

  • SQL 语句错误
  • 数据库连接失败
  • 查询执行异常

4. ClassNotFoundException

类未找到异常。

常出现在反射机制或动态加载类的场景中。


七、异常出现后程序会怎样

1. 默认情况:程序中断

如果异常出现后,没有被处理,那么程序通常会:

  • 停止执行
  • 在控制台输出异常信息
  • 给出异常类型和出错位置

例如:

public class Test {
public static void main(String[] args) {
int a = 10 / 0;
System.out.println("这句话不会执行");
}
}

运行后:

  • 异常被抛出
  • 程序终止
  • 后面的输出语句不会执行

2. 异常信息一般包括什么

异常信息通常包括:

  • 异常类型
  • 错误原因说明
  • 调用栈信息

例如:

Exception in thread "main" java.lang.ArithmeticException: / by zero
at Test.main(Test.java:3)

这说明:

  • 异常类型是 ArithmeticException
  • 原因是 / by zero
  • 错误发生在 Test.java 第 3 行

八、try-catch 异常捕获机制

1. 基本作用

try-catch 用来捕获并处理异常。

语法格式:

try {
// 可能发生异常的代码
} catch (异常类型 变量名) {
// 异常处理代码
}

2. 示例

public class Test {
public static void main(String[] args) {
try {
int a = 10 / 0;
System.out.println("try 中的后续语句");
} catch (ArithmeticException e) {
System.out.println("出现了算术异常");
}

System.out.println("程序继续执行");
}
}

输出结果说明:

  • 10 / 0 出现异常
  • try 中异常后面的代码不再执行
  • 进入 catch
  • 异常被处理后,程序继续执行 catch 后面的代码

3. 执行流程

没有异常

  • 执行 try
  • 跳过 catch
  • 继续往后执行

有异常

  • 执行 try
  • 发生异常,后续 try 代码停止
  • 找匹配的 catch
  • 执行对应 catch
  • 再继续往后执行

九、多个 catch

一个 try 后面可以跟多个 catch,用于处理不同类型的异常。

示例:

public class Test {
public static void main(String[] args) {
try {
String s = null;
System.out.println(s.length());
} catch (ArithmeticException e) {
System.out.println("算术异常");
} catch (NullPointerException e) {
System.out.println("空指针异常");
} catch (Exception e) {
System.out.println("其他异常");
}
}
}

1. 匹配原则

异常会按照 catch 的顺序,从上到下匹配。

一旦匹配成功:

  • 后面的 catch 不再执行

2. 注意顺序

如果写成:

catch (Exception e) { }
catch (NullPointerException e) { }

这通常是错误的,因为:

  • Exception 是父类
  • 它已经把后面的子类异常全接住了

因此,多个 catch 的顺序通常应该是:

子类异常在前,父类异常在后。


十、finally 语句块

1. 基本作用

finally 用于表示:

无论是否发生异常,通常都要执行的代码。

语法:

try {
// 可能异常的代码
} catch (异常类型 e) {
// 异常处理
} finally {
// 一般都会执行
}

2. 典型用途

最常见的用途是资源释放,例如:

  • 关闭文件流
  • 关闭数据库连接
  • 关闭网络连接

因为这些资源不管程序有没有出错,最后通常都应该关闭。

3. 示例

public class Test {
public static void main(String[] args) {
try {
int a = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("捕获到异常");
} finally {
System.out.println("finally 执行");
}
}
}

输出中 finally 仍然会执行。

4. finally 一定执行吗

一般情况下会执行,但并不是绝对的。

例如下面情况可能不会执行:

  • 程序在执行前被强制终止
  • 调用了 System.exit(0);
  • 进程被操作系统直接杀死

所以更准确地说:

在正常 JVM 执行流程下,finally 通常都会执行。


十一、try-catch-finally 的完整形式

完整写法:

try {
// 可能发生异常的代码
} catch (异常类型1 e) {
// 处理方式1
} catch (异常类型2 e) {
// 处理方式2
} finally {
// 最终执行代码
}

1. 组合关系

合法形式

  • try-catch
  • try-finally
  • try-catch-finally

非法形式

  • 只有 try
  • 只有 catch
  • 只有 finally

也就是说:

try 后面必须跟 catch 或 finally,至少一个。


十二、异常对象常用方法

在 catch 中,捕获到的异常其实是一个对象。

例如:

catch (Exception e) {
}

这里的 e 就是异常对象。

1. printStackTrace()

打印完整异常信息和调用栈。

e.printStackTrace();

这是调试时最常用的方法之一。

2. getMessage()

获取异常描述信息。

System.out.println(e.getMessage());

3. toString()

返回异常类名和异常信息。

System.out.println(e.toString());

4. 示例

try {
int a = 10 / 0;
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println(e.toString());
e.printStackTrace();
}


十三、throw 关键字

1. 作用

throw 用于:

手动抛出一个异常对象。

语法:

throw new 异常类名("异常信息");

2. 示例

public class Test {
public static void main(String[] args) {
int age = 1;
if (age < 0) {
throw new RuntimeException("年龄不能为负数");
}
}
}

这表示程序员主动认为这里是非法情况,于是主动抛出异常。

3. 使用场景

当程序发现某些条件不符合要求时,可以主动中断流程并抛出异常。

例如:

  • 参数非法
  • 数据状态不正确
  • 业务条件不满足

十四、throws 关键字

1. 作用

throws 用于写在方法声明后面,表示:

当前方法可能抛出哪些异常,交给调用者处理。

语法:

返回值类型 方法名(参数列表) throws 异常类名1, 异常类名2 {
}

2. 示例

import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class Test {
public static void readFile() throws FileNotFoundException {
FileInputStream fis = new FileInputStream("a.txt");
}
}

这表示:

  • readFile() 方法内部可能抛出 FileNotFoundException
  • 但当前方法自己不处理
  • 交给调用该方法的人去处理

3. throw 和 throws 的区别

这是常考点。

throw

  • 用在方法内部
  • 后面跟异常对象
  • 表示“抛出一个具体异常”

throws

  • 用在方法声明处
  • 后面跟异常类型
  • 表示“声明可能抛出哪些异常”

十五、方法重写与异常

在继承中,子类重写父类方法时,也会涉及异常规则。

1. 基本原则

子类重写父类方法时:

  • 抛出的检查异常不能比父类更大

也就是说,子类不能随意扩大异常范围。

2. 原因

因为父类引用调用方法时,编译器是按照父类方法声明来判断异常的。 如果子类突然抛出一个更大的受查异常,会破坏原有约定。

3. 初学阶段怎么记

可以先记一句:

重写方法时,子类抛出的受查异常范围不能超过父类。


十六、自定义异常

很多时候,Java 自带的异常类并不能完全表达我们的业务含义。 这时就可以自定义异常类。

1. 为什么要自定义异常

例如系统中有这样一种业务规则:

  • 用户年龄不能小于 0
  • 注册时用户名不能为空
  • 转账金额必须大于 0

如果全部都直接抛:

throw new RuntimeException("出错了");

虽然也能用,但语义不清晰。 如果自定义异常类,含义会更明确。

2. 自定义异常的方式

通常可以继承:

  • Exception
  • RuntimeException

继承 Exception

表示受查异常。

继承 RuntimeException

表示运行时异常。

3. 示例:自定义运行时异常

class AgeIllegalException extends RuntimeException {
public AgeIllegalException() {
}

public AgeIllegalException(String message) {
super(message);
}
}

使用:

public class Test {
public static void main(String[] args) {
int age = 1;
if (age < 0) {
throw new AgeIllegalException("年龄不能小于 0");
}
}
}

这样程序的异常含义就更明确了。

4. 示例:自定义受查异常

class LoginException extends Exception {
public LoginException() {
}

public LoginException(String message) {
super(message);
}
}

方法声明中:

public void login(String password) throws LoginException {
if (!"123456".equals(password)) {
throw new LoginException("密码错误");
}
}


十七、finally 与 return 的关系

这是一个比较经典、也比较容易出错的点。

1. 先看示例

public class Test {
public static int test() {
try {
return 10;
} finally {
System.out.println("finally 执行");
}
}
}

结果:

  • finally 还是会执行

2. 为什么会这样

因为 return 并不是一写出来就立刻彻底结束。 在方法真正返回前,JVM 还会去执行 finally。

3. 更复杂的情况

public class Test {
public static int test() {
try {
return 10;
} finally {
return 20;
}
}
}

最终返回值是:

20

说明:

不建议在 finally 中写 return。

因为这样会让程序逻辑变得很混乱,也可能掩盖原本的异常或返回结果。


十八、JDK7 之后的资源自动关闭

在早期写法中,IO 流通常这样处理:

FileInputStream fis = null;
try {
fis = new FileInputStream("a.txt");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

这种写法很安全,但比较繁琐。

从 JDK7 开始,可以使用:

try(资源对象声明) {
// 使用资源
}

示例:

import java.io.FileInputStream;

public class Test {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("a.txt")) {
System.out.println("文件打开成功");
} catch (Exception e) {
e.printStackTrace();
}
}
}

1. 优点

  • 代码更简洁
  • 自动关闭资源
  • 更不容易遗漏释放操作

2. 前提

资源对象需要实现:

AutoCloseable

很多流类都已经实现了这个接口。


十九、异常处理中常见错误

1. 抓了异常却什么也不做

例如:

catch (Exception e) {
}

这叫“吞异常”。 程序看似没报错,但真实问题被隐藏了,后续非常难排查。

2. 一上来就 catch(Exception)

虽然这样写不一定错,但如果不加区分地全部捕获,会让异常处理过于粗糙。 很多时候更应该优先捕获更具体的异常类型。

3. 把运行时异常全靠 try-catch 掩盖

例如明明应该先判断空值,却直接用 try-catch 去包住空指针。 这种写法不优雅,也说明代码逻辑前置校验没做好。

4. 在 finally 中写复杂逻辑

finally 本来应该用于:

  • 收尾
  • 释放资源
  • 执行必要清理

不适合写太复杂的业务逻辑。

5. 自定义异常时语义不清

如果异常名和异常信息写得很含糊,例如:

  • MyException
  • "出错了"

那即使自定义了,也没有实际价值。 异常类名和异常提示应该尽量表达真实问题。


二十、什么时候该处理,什么时候该抛出

这是实际开发中很重要的一个问题。

1. 当前方法能解决,就处理

例如:

  • 用户输入错误,可以在当前界面提示重新输入
  • 文件路径错误,可以在当前层提示用户重新选择

这类问题当前层能消化,就可以直接处理。

2. 当前方法解决不了,就往上抛

例如底层工具方法只负责读取文件,它自己并不知道:

  • 出错后是重试
  • 还是提示用户
  • 还是终止流程

这时它更适合把异常抛给上层,让更高层决定如何处理。

3. 一般原则

可以先记住一句:

谁更清楚如何处理这个问题,谁就应该处理异常。


二十一、异常机制和程序健壮性

一个优秀程序的重要特点之一,就是“健壮”。

所谓健壮,指的是:

  • 面对异常输入不轻易崩溃
  • 能给出合理提示
  • 能保留必要日志
  • 能保证重要资源被正确释放

异常机制正是实现程序健壮性的重要基础。

例如在开发中:

  • 表单提交要校验数据
  • 文件上传要校验格式
  • 读取配置要考虑文件缺失
  • 网络请求要考虑超时和失败

这些都需要异常思维,而不是只写“理想路径”。


二十二、学习异常时最容易混淆的几个点

1. throw 和 throws

  • throw:真正抛异常对象
  • throws:声明可能抛出异常类型

2. 编译时异常和运行时异常

  • 编译时异常:编译器强制处理
  • 运行时异常:编译器不强制,但运行时会出问题

3. final、finally、finalize

这是三个完全不同的词。

final

  • 修饰类、方法、变量

finally

  • 异常处理中的最终执行块

finalize

  • Object 类中的方法,和垃圾回收相关
  • 现代开发中基本不作为重点使用

这三者千万不要混淆。


二十三、学习建议

1. 不要只背概念,要亲手制造异常

建议自己动手写下面这些小例子:

  • 除 0 异常
  • 数组越界异常
  • 空指针异常
  • 类型转换异常
  • 文件找不到异常

亲自看到异常信息,比单纯看书更容易记住。

2. 多比较“处理前”和“处理后”

例如:

  • 不加 try-catch 时程序怎样
  • 加了 try-catch 后程序怎样

这样才能真正理解异常机制的作用。

3. 重点抓住执行流程

异常这章最容易出错的地方,不是概念,而是流程。

一定要弄清:

  • 异常在哪里产生
  • try 中后面代码还会不会执行
  • 会进入哪个 catch
  • finally 会不会执行
  • 方法到底是处理了还是抛出了异常

4. 先掌握常见异常,再学自定义异常

学习顺序建议:

  • 常见运行时异常
  • try-catch-finally
  • throw / throws
  • 编译时异常
  • 自定义异常
  • 这样更顺。


    二十四、本章知识总结

    1. 异常的本质

    异常表示程序在运行过程中出现的不正常情况。 它不是单纯的“报错信息”,而是一种完整的错误处理机制。

    2. 异常体系

    Java 异常体系顶层是:

    • Throwable

    下面分为:

    • Error
    • Exception

    3. 异常分类

    Exception 主要分为:

    • 编译时异常
    • 运行时异常

    其中:

    • 编译时异常要求强制处理
    • 运行时异常通常反映代码逻辑问题

    4. 异常处理语法

    最常见的语法有:

    • try
    • catch
    • finally
    • throw
    • throws

    5. 关键区别

    • throw:抛出具体异常对象
    • throws:声明方法可能抛出的异常类型

    6. 开发中的重点

    • 不要吞异常
    • 能处理就处理,不能处理就抛出
    • 优先捕获具体异常
    • 注意资源释放
    • 必要时自定义异常

    二十五、结语

    Java 中的异常机制,是连接“程序能运行”和“程序能稳定运行”之间的一座桥梁。很多初学者刚开始学异常时,会觉得它只是几个关键字和一些报错信息,但实际上,异常体现的是一种更完整的编程思维:

    • 不只写正常情况
    • 还要考虑错误情况
    • 不只让代码跑起来
    • 还要让代码在出问题时保持可控

    真正优秀的程序,并不是从不出错,而是在出错时仍然能够:

    • 给出明确信息
    • 保证资源安全
    • 降低故障影响
    • 方便后续排查

    因此,学习异常这一章时,不能只把它当成一个知识点,而要把它看成 Java 程序设计中非常关键的一种“防御性思维”。 只有真正掌握了异常机制,后面学习 IO、集合、多线程、数据库、网络编程和项目开发时,代码才会更加规范,也更加稳定。


    二十六、附:常见语法速查表

    1. try-catch

    try {
    // 可能出异常的代码
    } catch (Exception e) {
    e.printStackTrace();
    }

    2. try-catch-finally

    try {
    // 业务代码
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    System.out.println("收尾操作");
    }

    3. throw

    throw new RuntimeException("参数非法");

    4. throws

    public void test() throws IOException {
    }

    5. 自定义异常

    class MyException extends RuntimeException {
    public MyException(String message) {
    super(message);
    }
    }

    6. 自动关闭资源

    try (FileInputStream fis = new FileInputStream("a.txt")) {
    // 使用资源
    }


    好的,你们本章就到此结束了,在本章我们主要理解了Java当中异常的运行机制。到此为止,Java中所有的语法部分也介绍完毕,下一章我们介绍Java中的常用类。

    赞(0)
    未经允许不得转载:171主机测评 » 【第六章】Java中的异常
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址