【Java加强】1 异常 | 打卡day1

- 第 157 篇 -
Date: 2026 - 02- 02
Author: 郑龙浩(仟墨)

懒散了一阵子,好久没学Java了,今天将之前学的内容重新复习了一遍,然后还有两篇1月份的笔记没有发布,现在发一下其中一篇

文章目录

  • 【Java加强】异常
    • [1 异常的介绍](#1 异常的介绍)
    • [2 异常的处理](#2 异常的处理)
      • [2.1 抛出异常 (**throws**) - 上报问题](#2.1 抛出异常 (throws) - 上报问题)
      • [2.2 捕获异常(**try...catch**) - 就地解决](#2.2 捕获异常(try…catch) - 就地解决)
    • [3 异常的作用 | 异常处理的案例](#3 异常的作用 | 异常处理的案例)
    • [4 自定义异常](#4 自定义异常)
      • [4.1 自定义异常的分类](#4.1 自定义异常的分类)
      • [4.2 自定义异常的步骤](#4.2 自定义异常的步骤)
    • [4.2 自定义异常的步骤](#4.2 自定义异常的步骤)
      • [4.3 案例 - 运行时异常](#4.3 案例 - 运行时异常)
      • [4.3 关于自定义异常的注意事项](#4.3 关于自定义异常的注意事项)

【Java加强】异常

本篇笔记创作时间: 2026-01-06

1 异常的介绍

程序运行过程中发生的不正常情况,会中断正常的程序执行流程。

  • 程序在运行时遇到的错误或意外情况
  • 比如:除以0、访问不存在的文件、数组越界、空指针等

异常分类

  • Error: 表示严重的、程序无法处理的系统级错误,比如内存溢出(OutOfMemoryError)。这类错误通常由JVM抛出,应用程序一般无法处理,因此开发人员通常不关心也不捕获Error。

  • Exception: 表示程序运行时可能出现的、可以被捕获和处理的问题。程序员可可以处理的。

    • 一种是运行时异常(RuntimeException),这种异常在写代码的时候,编译器不会提示错误,要等到运行程序时才会暴露出来。比如数组索引越界异常。
    • 另一种是编译时异常(CheckedException),这种异常在写代码的时候,编译器就会直接提示错误,要求必须处理,否则程序无法运行。比如日期解析异常。

    开发人员主要使用Exception及其子类来封装和处理程序中可能出现的问题。

Java报错的时候实际上是使用类报错的,而且比如抛出的NullPointerException报错,实际上就是一个类,且这个类就继承于其他类,这个其他类又继承于RuntimeException,也就是RuntimeExceptions实际上是个父类,它的下面有一堆的字类,用于报错提示。

  • 错误是用"类"来表示的 :当发生空指针错误时,Java 实际上是在背后 new了一个 NullPointerException类(子类)的对象,并把它"扔"了出来,我们才能在屏幕上看到这个错误。

  • 异常之间有"父子"关系NullPointerException这个类(子类)并不是独立的,它"继承"自另一个更通用的类,叫做 RuntimeException。我可以把 RuntimeException理解为运行时异常这个"大家族"的"总爸爸"。

  • 不存在名为CheckedException的异常,这个只是个分类

    RuntimeException, 和其他异常 都继承 Exception
    CheckedException异常不存在,这个只是个分类

    Throwable(所有异常/错误的父类)
    ├── Error(错误,程序无法处理)
    │ ├── OutOfMemoryError(内存溢出)
    │ └── StackOverflowError(栈溢出)

    └── Exception(异常,可以处理)
    ├── RuntimeException(运行时异常,可处理可不处理)
    │ ├── NullPointerException(空指针异常)
    │ ├── ArrayIndexOutOfBoundsException(数组越界)
    │ └── ArithmeticException(算术异常,如除以0)

    └── CheckedException(编译时异常,必须处理) -- 该异常不存在,仅是分类
    ├── IOException(IO异常)
    ├── FileNotFoundException(文件找不到)
    └── SQLException(数据库异常)

2 异常的处理

2.1 抛出异常 (throws) - 上报问题

  • 做法 :在定义方法时,使用 throws 关键字声明
  • 作用 :告诉调用这个方法的人:"我内部 可能会发生某种异常,但我不处理。如果真发生了,这个异常就扔给你去解决。"

Eg:这段代码的意思是: "我在方法内部不处理异常,谁调用我这个方法,谁就要负责处理可能出现的 IOExceptionFileNotFoundException异常。"

将可能会出现的IOExceptionFileNotFoundException两个异常抛出去了,谁调用谁处理

调用这个方法的地方怎么解决:调用这个方法的地方,就可以写一个捕获异常,将这两个代码的异常处理掉

java 复制代码
// 在方法上声明可能抛出的异常
public void readFile() throws IOException, FileNotFoundException {
    // 方法内部可能抛出这些异常
    // 调用者需要处理这些异常
    if (...) {
        throw new IOException("IOExceptiony异常,。。。有问题");
    } else if (...){
        throw new FileNotFoundException("FileNotFoundException异常,。。。有问题");
    }
}

// 简单点,甚至可以改成抛 Exception,也就是只要遇到异常就抛出
public void readFile() throws Exception {
    // 方法内部可能抛出异常(不管是什么异常,都抛出)
    // 调用者需要处理这些异常
}

2.2 捕获异常(try...catch) - 就地解决

  • 做法 :在方法内部,用 try{ }包裹可能出错的代码,用 catch{ }来专门处理特定异常。
  • 作用 :在出问题的地方立刻拦截并处理异常,防止程序直接崩溃,并给出备用方案。
java 复制代码
try {
    // 监视可能出现异常的代码!
    int result = 10 / 0;  // 这里会抛出ArithmeticException
    
} catch (ArithmeticException e) {
    // 处理算术异常
    System.out.println("不能除以零");
    
} catch (Exception e) {
    // 处理其他异常
    System.out.println("发生未知错误");
}

3 异常的作用 | 异常处理的案例

  • 定位程序bug的关键信息
  • 知上层调用者, 方法执行可能会出现的问题/异常
java 复制代码
package zhenglonghao.exception1;

public class Exception1 {

    public static void main(String[] args) {
        // 目标:搞清楚异常的作用
        System.out.println("程序开始执行...");

        try {
            // 注意:Java方法调用不支持参数命名,应改为 div(10, 0)
            System.out.println(div(10, 0));
            System.out.println("底层方法执行成功了");
        } catch (Exception e) {
            e.printStackTrace();  // 作用1:提供完整的错误定位信息
            System.out.println("底层方法执行失败了");
        }

        System.out.println("程序结束执行...");
    }

    // 需求:求2个数的除的结果,并返回这个结果
    public static int div(int a, int b) throws Exception { // 注意throws加了s
        if (b == 0) {
            // 作用2:通过抛出异常告知上层调用者,方法执行出现异常情况
            // 异常可以携带错误信息,中断当前方法执行,并向上传递
            throw new Exception("除数不能为0,您的参数有问题!"); // 注意throw没加s
        }

        int result = a / b;
        return result;
    }
}

/* 打印结果:(会有异常)
E:\dev\jdk25\bin\java.exe -javaagent:E:\SoftWare\IntelliJ_IDEA_2025.2.4\lib\idea_rt.jar=50429 -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath E:\learning\Java开发\code\javaseaiproject\out\production\day14-exception-2025-01-06 zhenglonghao.exception1.Exception1
程序开始执行...
底层方法执行失败了
程序结束执行...
java.lang.Exception: 除数不能为0,您的参数有问题!
    at zhenglonghao.exception1.Exception1.div(Exception1.java:26)
    at zhenglonghao.exception1.Exception1.main(Exception1.java:11)

Process finished with exit code 0

 */

4 自定义异常

4.1 自定义异常的分类

在Java中,当企业有特定的问题需要以异常形式进行管理,而Java标准库未提供对应的异常类时,就需要自定义异常。自定义异常主要分为以下两类:

  1. 自定义运行时异常

    • 定义继承自 java.lang.RuntimeException类。(实际上,RuntimeException也继承Exception类)

    • 特点:编译阶段不会强制检查和处理,代码能正常编译。异常在运行时可能出现,提醒方式相对不激进。

    • 创建与抛出 :重写构造器,在需要时通过 throw new 异常类名()创建并抛出。

  2. 自定义编译时异常

  • 定义继承自 java.lang.Exception类。

  • 特点:编译阶段就会检查,如果存在未被处理的此类异常,代码将无法通过编译,提醒方式相对激进。

  • 创建与抛出 :重写构造器,在需要时通过 throw new 异常类名()创建并抛出。

核心对比

特性 自定义运行时异常 自定义编译时异常
继承的父类 RuntimeException Exception
编译时检查 不检查 检查,不处理则编译报错
使用场景 提示不很严重、通常由程序逻辑错误导致的非强制性问题。 提示严重、必须被显式处理的强制性问题。
方法签名(是否在自定义类内部使用throw抛出异常) 方法签名不需要 throws声明(无需在自定义运行时异常的类中抛出异常) 方法签名必须throws声明(必须在自定义编译时异常的类中抛出异常)

一定要注意:

  • 自定义运行时异常(比如类名A),不需要在A中抛出异常(比如不需要写:throw new AgeTooYoungException("年龄未满18岁,禁止访问!您当前的年龄是:" + age);
  • 自定义编译时异常(比如类名B),则必须在B中抛出异常,也就是需要写出throw new .....

4.2 自定义异常的步骤

4.2 自定义异常的步骤

1. 继承父类

创建一个新类,并继承相应的异常父类。

  • 若需定义编译时异常 ,则继承 Exception类。
  • 若需定义运行时异常 ,则继承 RuntimeException类。

2. 重写构造器

在自定义异常类中,重写父类的构造器。通常至少需要提供一个可以传递错误信息的构造器(即带 String message参数的构造器),这是报告异常详情的关键。

3. 抛出异常

在程序代码中,当业务逻辑遇到特定错误或无效状态时,使用 throw关键字,实例化并抛出您的自定义异常对象,从而中断当前执行流并将问题上报。

总结而言 :定义一个继承自目标父类(ExceptionRuntimeException)的新类,为其重写构造器,随后即可AgeTooYoungException在需要的地方通过 throw来使用它。

4.3 案例 - 运行时异常

在一个模拟"网吧"的类中,使用方法判断年龄,年龄<18时抛出我们的自定义异常。

AgeTooYoungException.java 文件

该文件存储的是自定义的运行时异常会抛出的类

注意,刚开始理解错了的点

如果是运行时异常,是不是不需要在自定义的运行时异常的类中返回throw...的,而是需要在外面直接使用throw抛出

java 复制代码
package zhenglonghao.exception1;
/**
 * Date: 2025-01-06 Author: 郑龙浩
 * 这是个「自定义运行时异常」
 * 自定义的运行时异常:年龄太小异常
 * 1. 继承 RuntimeException 做爸爸。
 * 2. 重写 RuntimeException 的构造器。
 */
public class AgeTooYoungException extends RuntimeException { // 关键:继承 RuntimeException
    // 1. 无参构造器
    public AgeTooYoungException() {
    }
    // 2. 带消息的构造器(最常用,推荐重写这个)
    public AgeTooYoungException(String message) {
        super(message); // 调用父类构造器,把异常原因信息传进去
    }
}

CyberCafe.java 文件

运行测试

java 复制代码
package zhenglonghao.exception1;

import java.util.Scanner;

// Date: 2025-01-06 Author: 郑龙浩
// 自定义 「运行时的异常」
// 在一个模拟"网吧"的类中,在一个模拟"网吧"的类中,使用方法判断年龄,年龄<18时抛出我们的自定义异常。
public class

CyberCafe {
    public void enter(int age) {
        if (age < 18) {
            // 3. 哪里需要用这个异常,哪里就 throw
            // 因为它是运行时异常,所以方法签名上无需用 throws 声明
            throw new AgeTooYoungException("年龄未满18岁,禁止访问!您当前的年龄是:" + age);
        }
        System.out.println("欢迎光临,祝您玩得愉快!");
    }

    public static void main(String[] args) {
        CyberCafe cafe = new CyberCafe();
        System.out.println("网吧开始营业...");
        System.out.println("请输入您的年龄:");
        Scanner scanner = new Scanner(System.in);
        int age = scanner.nextInt();
        try {
            cafe.enter(age); // 如果是未成年,会抛出 AgeTooYoungException
        } catch (AgeTooYoungException e) {
            System.out.println("捕获到异常:" + e.getMessage());
        }
    }
}

4.3 关于自定义异常的注意事项

在 Java 里,尽量别自己定义那种"必须处理"的异常(编译时异常)

为啥呢?因为你一定义这种异常,别人用你的代码时就被强制要求要么 try-catch,要么也往上抛。结果就是:

  • 代码里到处是 try-catch,核心逻辑都看不清楚了。
  • 或者异常被一层层机械地往上抛,最后谁也没真正处理,很麻烦。

所以行业里的共识是:优先考虑用运行时异常。这样更灵活,调用方爱处理就处理,不处理也不会编译报错,代码干净很多。

简单总结

除非这个错误必须 让调用方当场处理(比如"账户余额不足"),否则都别定义编译时异常。绝大多数错误(像"参数传错了"、"连接超时了"),用自定义的运行时异常来表示就对了。

尽量使用运行,而非编译

相关推荐
去往火星2 小时前
Qt6 CMake 中引入 Qt Linguist 翻译功能
开发语言·qt
阿猿收手吧!2 小时前
【C++】atmoic原子操作与并发安全全解析
开发语言·c++·安全
Dingdangcat862 小时前
基于RetinaNet的建筑表面缺陷检测与识别系统研究_2
python
AllData公司负责人2 小时前
【亲测好用】实时开发平台能力演示
java·c语言·数据库
pcm1235672 小时前
设计C/S架构的IM通信软件(3)
java·c语言·架构
zz34572981132 小时前
C语言基础概念7
c语言·开发语言
会开花的二叉树2 小时前
Reactor网络库的连接管理核心:Connection类
开发语言·网络·php
凯子坚持 c2 小时前
C++基于微服务脚手架的视频点播系统---客户端(1)
开发语言·c++·微服务
袖清暮雨2 小时前
Python爬虫(Scrapy框架)
开发语言·爬虫·python·scrapy