Java中的异常

Java 异常详解

异常(Exception)是程序运行时发生的不正常情况(错误或意外),Java 通过异常处理机制让程序在出错时不会直接崩溃,而是能优雅地处理错误。

一、异常的核心概念

1. 异常的分类

Java 中所有异常都继承自 Throwable 类,主要分为两大分支:

  • Error(错误) :JVM 层面的严重问题(如内存溢出、虚拟机崩溃),程序无法处理,只能避免(如 StackOverflowErrorOutOfMemoryError)。
  • Exception(异常) :程序本身可以处理的问题,又分为:
    • 受检异常(Checked Exception) :编译时必须处理(捕获或声明抛出),如 IOExceptionSQLException
    • 非受检异常(Unchecked Exception) :运行时才会出现,编译时无需强制处理,如 NullPointerExceptionArrayIndexOutOfBoundsException(继承自 RuntimeException)。
2. 常见异常示例

表格

异常类型 说明
NullPointerException 调用空对象的方法 / 属性
ArrayIndexOutOfBounds 数组下标越界
ClassCastException 类型转换失败
ArithmeticException 算术错误(如除以 0)
IOException IO 操作失败(如文件读写)

二、异常的处理方式

Java 处理异常的核心是 try-catch-finallythrows/throw

1. 捕获异常(try-catch-finally)

语法

java

运行

复制代码
try {
    // 可能抛出异常的代码
} catch (异常类型1 变量名) {
    // 处理异常类型1
} catch (异常类型2 变量名) {
    // 处理异常类型2(注意:子类异常要写在父类前面)
} finally {
    // 无论是否发生异常,都会执行(常用于释放资源,如关闭流、数据库连接)
}

示例

java

运行

复制代码
public class ExceptionDemo {
    public static void main(String[] args) {
        int a = 10;
        int b = 0;
        
        try {
            // 可能抛出算术异常的代码
            int result = a / b;
            System.out.println("结果:" + result);
        } catch (ArithmeticException e) {
            // 捕获并处理异常
            System.out.println("错误:除数不能为 0");
            // 打印异常详细信息(调试用)
            e.printStackTrace();
        } finally {
            // 无论是否异常,都会执行
            System.out.println("程序执行完毕");
        }
    }
}

输出

plaintext

复制代码
错误:除数不能为 0
java.lang.ArithmeticException: / by zero
	at ExceptionDemo.main(ExceptionDemo.java:8)
程序执行完毕
2. 声明抛出异常(throws)

如果方法内部不想处理异常,可声明 "抛出",由调用者处理:

java

运行

复制代码
import java.io.FileReader;
import java.io.IOException;

// 声明抛出受检异常 IOException
public class ThrowsDemo {
    public static void readFile() throws IOException {
        // 读取文件可能抛出 IOException
        FileReader fr = new FileReader("test.txt");
        fr.close();
    }

    public static void main(String[] args) {
        try {
            // 调用者必须处理抛出的异常
            readFile();
        } catch (IOException e) {
            System.out.println("文件读取失败:" + e.getMessage());
        }
    }
}
3. 主动抛出异常(throw)

手动触发异常(常用于业务逻辑校验):

java

运行

复制代码
public class ThrowDemo {
    public static void checkAge(int age) {
        if (age < 18) {
            // 主动抛出运行时异常
            throw new IllegalArgumentException("年龄必须≥18");
        }
        System.out.println("年龄合法");
    }

    public static void main(String[] args) {
        try {
            checkAge(16);
        } catch (IllegalArgumentException e) {
            System.out.println("错误:" + e.getMessage());
        }
    }
}

三、自定义异常

当系统内置异常无法满足业务需求时,可自定义异常:

步骤:
  1. 继承 Exception(受检)或 RuntimeException(非受检);
  2. 提供无参构造和带消息的构造方法。

示例

java

运行

复制代码
// 自定义受检异常
public class AgeException extends Exception {
    // 无参构造
    public AgeException() {
        super();
    }

    // 带异常信息的构造
    public AgeException(String message) {
        super(message);
    }
}

// 使用自定义异常
public class CustomExceptionDemo {
    public static void checkAge(int age) throws AgeException {
        if (age < 0 || age > 150) {
            throw new AgeException("年龄必须在 0-150 之间");
        }
        System.out.println("年龄有效");
    }

    public static void main(String[] args) {
        try {
            checkAge(200);
        } catch (AgeException e) {
            System.out.println("异常:" + e.getMessage());
        }
    }
}

四、异常处理的最佳实践

  1. 不要捕获 Throwable(包含 Error,无法处理);
  2. 避免空的 catch 块(会隐藏错误);
  3. 优先捕获具体异常(而非直接捕获 Exception);
  4. finally 中避免抛出异常(会覆盖原异常);
  5. 受检异常用于 "可恢复的错误",非受检异常用于 "编程错误"。

总结

  1. Java 异常根类是 Throwable,核心分支为 Error(不可处理)和 Exception(可处理),Exception 又分受检(编译时处理)和非受检(运行时处理);
  2. 异常处理的核心方式:try-catch-finally(捕获处理)、throws(声明抛出)、throw(主动抛出);
  3. 自定义异常需继承 ExceptionRuntimeException,用于适配业务场景的错误提示。
相关推荐
二哈赛车手4 小时前
新人笔记---ApiFox的一些常见使用出错
java·笔记·spring
为何创造硅基生物5 小时前
C语言 结构体内存对齐规则(通俗易懂版)
c语言·开发语言
吃好睡好便好5 小时前
在Matlab中绘制横直方图
开发语言·学习·算法·matlab
栗子~~5 小时前
JAVA - 二层缓存设计(本地缓冲+redis缓冲+广播所有本地缓冲失效) demo
java·redis·缓存
星寂樱易李5 小时前
iperf3 + Python-- 网络带宽、网速、网络稳定性
开发语言·网络·python
YDS8295 小时前
DeepSeek RAG&MCP + Agent智能体项目 —— RAG知识库的搭建和接口实现
java·ai·springboot·agent·rag·deepseek
仰泳之鹅5 小时前
【C语言】自定义数据类型2——联合体与枚举
c语言·开发语言·算法
之歆6 小时前
DAY_12JavaScript DOM 完全指南(二):实战与性能篇
开发语言·前端·javascript·ecmascript
未若君雅裁6 小时前
MyBatis 一级缓存、二级缓存与清理机制
java·缓存·mybatis
cen__y7 小时前
Linux12(Git01)
linux·运维·服务器·c语言·开发语言·git