Java入门( 异常 )

目录

一、什么是异常?打破程序的正常流程

常见异常示例

[二、Java 异常体系结构:理清继承关系,不混淆概念](#二、Java 异常体系结构:理清继承关系,不混淆概念)

核心继承结构

三大核心类的区别

三、异常的处理方式:从防御式编程到核心关键字

[3.1 两种防御式编程思想](#3.1 两种防御式编程思想)

[LBYL:事前防御型(Look Before You Leap)](#LBYL:事前防御型(Look Before You Leap))

[EAFP:事后处理型(It's Easier to Ask Forgiveness than Permission)](#EAFP:事后处理型(It's Easier to Ask Forgiveness than Permission))

[3.2 手动抛出异常:throw](#3.2 手动抛出异常:throw)

语法格式

实战示例:参数合法性校验

[throw 使用注意事项](#throw 使用注意事项)

[3.3 声明异常:throws](#3.3 声明异常:throws)

语法格式

实战示例:文件操作声明编译时异常

[throws 使用注意事项](#throws 使用注意事项)

[3.4 捕获并处理异常:try-catch](#3.4 捕获并处理异常:try-catch)

语法格式

实战示例:多异常捕获与处理

运行结果

[try-catch 使用关键注意事项](#try-catch 使用关键注意事项)

[3.5 必执行的代码块:finally](#3.5 必执行的代码块:finally)

语法格式

核心场景:资源释放(全新示例)

[测试结果 1:输入正确整数](#测试结果 1:输入正确整数)

[测试结果 2:输入非整数](#测试结果 2:输入非整数)

[finally 的特殊注意事项](#finally 的特殊注意事项)

四、异常的处理流程:跟着调用栈走,理清执行顺序

异常处理完整执行流程

实战示例:异常的向上传播

运行结果

五、自定义异常:贴合业务场景,让异常更有意义

[5.1 自定义异常的实现步骤](#5.1 自定义异常的实现步骤)

[5.2 实战示例:用户登陆业务的自定义异常](#5.2 实战示例:用户登陆业务的自定义异常)

[步骤 1:实现自定义异常类](#步骤 1:实现自定义异常类)

[步骤 2:在业务代码中抛出自定义异常](#步骤 2:在业务代码中抛出自定义异常)

[步骤 3:调用业务方法,处理自定义异常](#步骤 3:调用业务方法,处理自定义异常)

运行结果

[5.3 自定义异常的选型建议](#5.3 自定义异常的选型建议)

六、异常处理的最佳实践

七、总结


在 Java 开发的道路上,异常处理是绕不开的核心知识点。无论是新手调试代码时遇到的NullPointerException,还是开发企业级项目时处理的网络、文件 IO 异常,掌握规范的异常处理方式,能让我们的代码更健壮、更易维护,还能大幅降低线上问题的排查成本。本文将从异常的核心概念出发,逐步拆解 Java 异常体系、处理方式、执行流程,最后手把手教你实现自定义异常,让你彻底吃透 Java 异常处理。

一、什么是异常?打破程序的正常流程

异常是程序运行过程中 发生的非正常行为 / 错误状态,它会打断程序的正常执行流程,需要开发者通过特定方式进行处理。

在开发中,我们无法避免各类异常场景:比如除数为 0 的算术错误、访问数组不存在的下标、调用空对象的方法、读取不存在的文件、网络请求超时等。这些场景无法通过普通的逻辑判断完全规避,而 Java 为每一种异常场景都提供了对应的类来描述,让我们能精准定位和处理问题。

常见异常示例

java 复制代码
/**
 * 常见运行时异常演示
 */
public class CommonExceptionDemo {
    public static void main(String[] args) {
        // 1. 算术异常:ArithmeticException
        int a = 10;
        int b = 0;
        // System.out.println(a / b);

        // 2. 数组越界异常:ArrayIndexOutOfBoundsException
        String[] strArr = {"Java", "Python", "C++"};
        // System.out.println(strArr[5]);

        // 3. 空指针异常:NullPointerException
        String str = null;
        // System.out.println(str.length());

        // 4. 类型转换异常:ClassCastException
        Object obj = new Integer(100);
        // System.out.println((String) obj);
    }
}

取消上述代码的注释,运行后会看到控制台抛出对应的异常信息,包含异常类型、异常原因和出错的代码行,这也是 Java 异常给我们的核心调试线索。

二、Java 异常体系结构:理清继承关系,不混淆概念

Java 为了对不同类型的异常和错误进行分类管理,设计了一套清晰的异常体系,其顶层类是java.lang.Throwable,所有异常和错误都直接或间接继承自该类。

核心继承结构

复制代码
Throwable
├─ Error:JVM级别的严重错误,无法通过代码处理
│  ├─ StackOverflowError:栈溢出错误(如递归无终止条件)
│  └─ OutOfMemoryError:内存溢出错误(OOM)
└─ Exception:程序级别的异常,开发者可通过代码处理
   ├─ 编译时异常(受检查异常 Checked Exception):编译期必须处理
   │  ├─ IOException:IO操作相关异常(如文件读取、网络请求)
   │  ├─ SQLException:数据库操作相关异常
   │  └─ ClassNotFoundException:类加载失败异常
   └─ 运行时异常(非受检查异常 Unchecked Exception):运行期才会出现,可按需处理
      ├─ NullPointerException:空指针异常
      ├─ ArrayIndexOutOfBoundsException:数组越界异常
      ├─ ArithmeticException:算术异常
      └─ ClassCastException:类型转换异常

三大核心类的区别

  1. Error :Java 虚拟机无法解决的严重问题,属于系统级错误,一旦发生程序基本无法恢复,只能提前预防。比如递归调用无终止条件会导致StackOverflowError,创建大量对象未释放会导致OutOfMemoryError
  2. 编译时异常(Checked Exception) :在程序编译阶段 就会被检测到的异常,编译器强制要求开发者必须处理(捕获或抛出),否则代码无法通过编译。比如读取文件时的FileNotFoundException,必须显式处理。
  3. 运行时异常(Unchecked Exception) :继承自RuntimeException的异常,在程序运行阶段才会触发,编译器不强制处理。这类异常通常是由于开发者的代码逻辑错误导致的,比如空指针、数组越界,建议通过优化代码逻辑避免,而非被动处理。

重要区分 :编译期的语法错误 (如把System.out.println写成system.out.println)不属于异常,只是代码书写错误,编译器会直接提示,无法生成 class 文件;而异常是代码编译通过后,JVM 执行时发生的错误。

三、异常的处理方式:从防御式编程到核心关键字

在处理异常前,我们需要了解两种编程思想:事前防御事后处理 ,Java 异常处理的核心基于后者,同时提供了 5 个核心关键字:throwthrowstrycatchfinally,掌握这 5 个关键字,就能处理绝大多数异常场景。

3.1 两种防御式编程思想

LBYL:事前防御型(Look Before You Leap)

在执行操作前,对所有可能出现的问题进行充分检查,正常流程和错误处理流程混在一起,代码可读性差。

java 复制代码
/**
 * 事前防御型编程示例:用户登陆
 */
public class LBYLDemo {
    public static void main(String[] args) {
        String username = "test";
        String password = "123";

        // 检查用户名是否为空
        if (username == null || username.isEmpty()) {
            System.out.println("错误:用户名为空");
            return;
        }
        // 检查密码是否为空
        if (password == null || password.isEmpty()) {
            System.out.println("错误:密码为空");
            return;
        }
        // 检查用户名密码是否正确
        if (!"admin".equals(username) || !"admin123".equals(password)) {
            System.out.println("错误:用户名或密码错误");
            return;
        }

        System.out.println("登陆成功");
    }
}

缺陷 :代码中大量的if判断让核心业务逻辑被淹没,后期维护难度大。

EAFP:事后处理型(It's Easier to Ask Forgiveness than Permission)

先执行操作,遇到问题再捕获处理,将正常流程和错误流程分离,代码更清晰,这也是 Java 异常处理的核心思想。

java 复制代码
/**
 * 事后处理型编程示例:用户登陆
 */
public class EAFPDemo {
    public static void main(String[] args) {
        String username = "test";
        String password = "123";
        try {
            // 直接执行核心业务逻辑,不做前置检查
            login(username, password);
            System.out.println("登陆成功");
        } catch (NullPointerException e) {
            System.out.println("错误:用户名或密码为空");
        } catch (IllegalArgumentException e) {
            System.out.println("错误:" + e.getMessage());
        }
    }

    private static void login(String username, String password) {
        if (username == null || password == null) {
            throw new NullPointerException();
        }
        if (!"admin".equals(username) || !"admin123".equals(password)) {
            throw new IllegalArgumentException("用户名或密码错误");
        }
    }
}

优势 :核心业务逻辑login()方法简洁,错误处理集中在catch块,开发者更关注正常流程,代码可读性和可维护性大幅提升。

3.2 手动抛出异常:throw

在编写程序时,如果检测到非法的业务逻辑或参数错误 ,需要主动将错误信息告知调用者,此时可以使用throw关键字手动抛出一个指定的异常对象。

语法格式
java 复制代码
throw new 异常类名("异常产生的原因");
实战示例:参数合法性校验
java 复制代码
/**
 * throw 手动抛出异常示例:获取集合指定下标元素
 */
import java.util.List;

public class ThrowDemo {
    public static <T> T getListElement(List<T> list, int index) {
        // 校验集合是否为null
        if (list == null) {
            throw new NullPointerException("传递的集合对象为null,无法获取元素");
        }
        // 校验下标是否合法
        if (index < 0 || index >= list.size()) {
            throw new IndexOutOfBoundsException("传递的下标" + index + "越界,集合长度为" + list.size());
        }
        // 校验通过,返回元素
        return list.get(index);
    }

    public static void main(String[] args) {
        List<String> list = List.of("Java", "异常", "处理");
        // 正常获取
        System.out.println(getListElement(list, 1));
        // 下标越界,手动抛出异常
        // System.out.println(getListElement(list, 5));
        // 集合为null,手动抛出异常
        // System.out.println(getListElement(null, 0));
    }
}
throw 使用注意事项
  1. throw必须写在方法体内部
  2. 抛出的对象必须是Exception或其子类的实例;
  3. 抛出运行时异常 (如NullPointerException),调用者可按需处理,编译器不强制;
  4. 抛出编译时异常 (如IOException),调用者必须处理(捕获或抛出),否则代码无法编译;
  5. 异常一旦抛出,其后的代码将不会执行

3.3 声明异常:throws

如果当前方法没有能力处理 抛出的异常,或者希望将异常处理的责任转移给调用者,此时可以使用throws关键字在方法声明处声明该方法可能抛出的异常。

语法格式
java 复制代码
修饰符 返回值类型 方法名(参数列表) throws 异常类型1, 异常类型2... {
    // 方法体,可能抛出异常
}
实战示例:文件操作声明编译时异常
java 复制代码
/**
 * throws 声明异常示例:文件读取
 */
import java.io.File;
import java.io.FileReader;
import java.io.FileNotFoundException;

public class ThrowsDemo {
    // 声明文件未找到异常,交给调用者处理
    public static FileReader openFile(String filePath) throws FileNotFoundException {
        File file = new File(filePath);
        // FileNotFoundException是编译时异常,此处不处理,声明后抛出
        return new FileReader(file);
    }

    public static void main(String[] args) {
        try {
            // 调用声明异常的方法,必须处理异常
            FileReader fr = openFile("test.txt");
            System.out.println("文件打开成功");
            fr.close();
        } catch (FileNotFoundException e) {
            System.out.println("异常原因:" + e.getMessage());
        }
    }
}
throws 使用注意事项
  1. throws必须跟在方法参数列表之后
  2. 声明的异常必须是Exception或其子类;
  3. 方法内部抛出多个异常时,throws后用逗号 分隔多个异常类型;若异常之间有父子关系,直接声明父类异常 即可(如FileNotFoundException继承自IOException,可直接声明throws IOException);
  4. 调用声明了编译时异常 的方法,调用者必须处理(try-catch捕获或继续throws抛出);调用声明了运行时异常的方法,编译器不强制处理。

3.4 捕获并处理异常:try-catch

throws只是将异常转移给调用者,并未真正处理异常;而try-catch是 Java 中处理异常的核心方式,能捕获异常并对其进行处理,让程序在发生异常后继续执行。

语法格式
java 复制代码
try {
    // 可能抛出异常的代码块(监控区)
} catch (异常类型1 异常对象名) {
    // 处理异常类型1的代码(捕获区)
} catch (异常类型2 异常对象名) {
    // 处理异常类型2的代码
}
// 可选:finally块,下文单独讲解
实战示例:多异常捕获与处理
java 复制代码
/**
 * try-catch 捕获异常示例:多异常处理
 */
public class TryCatchDemo {
    public static void calculate(int a, int b, int[] arr) {
        try {
            System.out.println("a / b = " + (a / b));
            System.out.println("数组下标0的元素:" + arr[0]);
        } catch (ArithmeticException e) {
            // 处理算术异常
            System.out.println("处理算术异常:" + e.getMessage());
        } catch (NullPointerException e) {
            // 处理空指针异常
            System.out.println("处理空指针异常:数组对象为null");
        } catch (ArrayIndexOutOfBoundsException e) {
            // 处理数组越界异常
            System.out.println("处理数组越界异常:" + e.getMessage());
        }
    }

    public static void main(String[] args) {
        // 测试1:除数为0
        calculate(10, 0, new int[]{1,2});
        System.out.println("===== 分割线 =====");
        // 测试2:数组为null
        calculate(10, 2, null);
        System.out.println("===== 分割线 =====");
        // 测试3:数组越界(空数组)
        calculate(10, 2, new int[]{});

        // 异常处理后,后续代码正常执行
        System.out.println("程序执行完成");
    }
}
运行结果
复制代码
处理算术异常:/ by zero
===== 分割线 =====
处理空指针异常:数组对象为null
===== 分割线 =====
处理数组越界异常:Index 0 out of bounds for length 0
程序执行完成

可以看到,即使发生了异常,经过try-catch处理后,程序的后续代码依然能正常执行,这也是异常处理的核心目的。

try-catch 使用关键注意事项
  1. try块中抛出异常的位置后续代码不会执行

  2. 异常捕获遵循类型匹配原则 :只有catch的异常类型与try中抛出的异常类型一致 ,或为其父类,才能捕获到异常;

  3. 处理多个不同类型的异常 时,需注意子类异常在前,父类异常在后 ,否则会出现语法错误(父类异常会捕获所有子类异常,后续的子类异常catch块永远无法执行);

  4. 若多个异常的处理逻辑完全相同 ,可使用 ** 竖线 |** 合并捕获,简化代码:

    java 复制代码
    catch (ArithmeticException | NullPointerException | ArrayIndexOutOfBoundsException e) {
        System.out.println("处理异常:" + e.getMessage());
    }
  5. 可以使用Exception捕获所有异常 (因为Exception是所有程序级异常的父类),但不推荐:会掩盖具体的异常类型,不利于问题排查,仅适用于通用的异常兜底处理。

3.5 必执行的代码块:finally

在程序开发中,有些代码无论是否发生异常,都必须执行 ,比如打开的文件流、数据库连接、网络连接等资源的释放,否则会造成资源泄漏finally块就是为了解决这个问题,它配合try-catch使用,里面的代码永远会被执行

语法格式
java 复制代码
try {
    // 可能抛出异常的代码
} catch (异常类型 e) {
    // 处理异常的代码
} finally {
    // 无论是否发生异常,都会执行的代码(资源释放为主)
}
核心场景:资源释放(全新示例)
java 复制代码
/**
 * finally 块示例:资源释放(Scanner)
 */
import java.util.Scanner;
import java.util.InputMismatchException;

public class FinallyDemo {
    public static int getIntInput() {
        Scanner sc = new Scanner(System.in);
        try {
            System.out.print("请输入一个整数:");
            // 尝试获取整数输入
            int num = sc.nextInt();
            return num;
        } catch (InputMismatchException e) {
            System.out.println("输入类型错误,不是整数");
            return -1;
        } finally {
            // 无论是否输入正确,都关闭Scanner,释放资源
            System.out.println("执行finally块:关闭Scanner资源");
            sc.close();
        }
    }

    public static void main(String[] args) {
        int num = getIntInput();
        System.out.println("获取到的数字:" + num);
    }
}
测试结果 1:输入正确整数
复制代码
请输入一个整数:100
执行finally块:关闭Scanner资源
获取到的数字:100
测试结果 2:输入非整数
复制代码
请输入一个整数:abc
输入类型错误,不是整数
执行finally块:关闭Scanner资源
获取到的数字:-1

可以看到,无论try块中是否发生异常,finally块的代码都会执行,完美解决了资源释放的问题。

finally 的特殊注意事项
  1. finally块的执行时机:在方法返回之前 (即使trycatch中有return语句,也会先执行finally块,再执行return);
  2. finally块中也有return语句,会覆盖 trycatch中的return结果,强烈不建议finally中写return(编译器会给出警告);
  3. finally块唯一不执行的情况:程序执行到try/catch块时,调用了System.exit(0)(强制终止 JVM),此时 JVM 直接退出,所有代码都不再执行。

四、异常的处理流程:跟着调用栈走,理清执行顺序

要彻底理解异常处理,必须理清异常的传播和处理流程 ,而核心就是方法调用栈 :Java 中方法之间的调用关系会被 JVM 存储在虚拟机栈 中,当发生异常时,异常会沿着调用栈从下往上传播,直到被捕获处理,若最终无人处理,则由 JVM 接管,程序异常终止。

异常处理完整执行流程

  1. 程序先执行try块中的代码;
  2. try块中未发生异常 ,跳过catch块,直接执行finally块,再执行try-catch-finally后的代码;
  3. try块中发生异常 ,立即终止try块后续代码,匹配catch块的异常类型:
    • 找到匹配的异常类型 :执行对应catch块的处理代码,再执行finally块,最后执行后续代码;
    • 未找到匹配的异常类型 :先执行finally块,再将异常向上传播给上层调用者;
  4. 上层调用者重复步骤 3,若所有调用者都未处理异常,最终传递到main方法;
  5. main方法也未处理异常,异常会被JVM 接管 ,JVM 会打印异常信息(类型、原因、调用栈),并强制终止程序,main方法后续代码不再执行。

实战示例:异常的向上传播

java 复制代码
/**
 * 异常处理流程示例:异常向上传播
 */
public class ExceptionFlowDemo {
    // 方法3:抛出数组越界异常
    public static void method3() {
        int[] arr = {1,2,3};
        System.out.println(arr[10]); // 抛出异常
    }

    // 方法2:调用method3,未处理异常
    public static void method2() {
        method3();
    }

    // 方法1:调用method2,捕获并处理异常
    public static void method1() {
        try {
            method2();
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("method1捕获到异常:" + e.getMessage());
        }
    }

    public static void main(String[] args) {
        method1();
        // 异常被处理,后续代码正常执行
        System.out.println("main方法后续代码执行");
    }
}
运行结果
java 复制代码
method1捕获到异常:Index 10 out of bounds for length 3
main方法后续代码执行

若删除method1中的try-catch,异常会传播到main方法,若main方法也不处理,JVM 会接管,程序终止,main方法后续代码不再执行。

五、自定义异常:贴合业务场景,让异常更有意义

Java 内置了丰富的异常类,但这些异常类都是通用的 ,无法精准描述实际开发中的业务异常 ,比如用户登陆时的 "用户名不存在"、"密码错误",订单操作时的 "订单不存在"、"库存不足" 等。此时我们需要自定义异常类,贴合业务场景,让异常信息更精准,便于问题排查和业务处理。

5.1 自定义异常的实现步骤

Java 中自定义异常的核心是继承,遵循以下两步即可:

  1. 自定义异常类,继承自Exception(编译时异常,受检查)或RuntimeException(运行时异常,非受检查);
  2. 实现带 String 类型参数的构造方法 ,将异常原因通过super()传递给父类构造方法(便于通过getMessage()获取异常原因)。

5.2 实战示例:用户登陆业务的自定义异常

我们针对用户登陆场景,自定义两个业务异常:UserNameNotExistException(用户名不存在)、PasswordErrorException(密码错误),并在业务代码中抛出和处理。

步骤 1:实现自定义异常类
java 复制代码
/**
 * 自定义异常:用户名不存在(继承Exception,编译时异常)
 */
public class UserNameNotExistException extends Exception {
    // 构造方法,传递异常原因
    public UserNameNotExistException(String message) {
        super(message);
    }
}

/**
 * 自定义异常:密码错误(继承Exception,编译时异常)
 */
public class PasswordErrorException extends Exception {
    public PasswordErrorException(String message) {
        super(message);
    }
}

可选优化 :若希望自定义异常为运行时异常,只需将父类改为RuntimeException,编译器不强制处理。

步骤 2:在业务代码中抛出自定义异常
java 复制代码
/**
 * 用户登陆业务类
 */
public class UserLoginService {
    // 模拟数据库中的用户信息
    private static final String DB_USERNAME = "admin";
    private static final String DB_PASSWORD = "admin123456";

    /**
     * 登陆方法,抛出自定义业务异常
     * @param username 用户名
     * @param password 密码
     * @throws UserNameNotExistException 用户名不存在
     * @throws PasswordErrorException    密码错误
     */
    public void login(String username, String password) throws UserNameNotExistException, PasswordErrorException {
        // 校验用户名
        if (!DB_USERNAME.equals(username)) {
            throw new UserNameNotExistException("用户名[" + username + "]不存在");
        }
        // 校验密码
        if (!DB_PASSWORD.equals(password)) {
            throw new PasswordErrorException("密码错误,请重新输入");
        }
    }
}
步骤 3:调用业务方法,处理自定义异常
java 复制代码
/**
 * 测试自定义异常:用户登陆
 */
public class CustomExceptionTest {
    public static void main(String[] args) {
        UserLoginService loginService = new UserLoginService();
        // 测试1:用户名不存在
        String username = "test";
        String password = "admin123456";

        try {
            loginService.login(username, password);
            System.out.println("登陆成功!");
        } catch (UserNameNotExistException e) {
            System.out.println("登陆失败:" + e.getMessage());
            // 可做后续处理,如跳转到注册页面
        } catch (PasswordErrorException e) {
            System.out.println("登陆失败:" + e.getMessage());
            // 可做后续处理,如提示密码找回
        }

        // 测试2:密码错误
        System.out.println("===== 分割线 =====");
        username = "admin";
        password = "123";
        try {
            loginService.login(username, password);
            System.out.println("登陆成功!");
        } catch (UserNameNotExistException | PasswordErrorException e) {
            System.out.println("登陆失败:" + e.getMessage());
        }
    }
}
运行结果
复制代码
登陆失败:用户名[test]不存在
===== 分割线 =====
登陆失败:密码错误,请重新输入

可以看到,自定义异常能精准描述业务中的错误场景,让异常处理更贴合实际业务,同时异常信息更直观,便于开发和运维人员排查问题。

5.3 自定义异常的选型建议

  • 若希望编译器强制处理 该异常(如核心业务异常,必须显式处理),让自定义异常继承Exception(编译时异常);
  • 若该异常可通过代码逻辑避免 ,或希望简化代码(不强制处理),让自定义异常继承RuntimeException(运行时异常);
  • 自定义异常的命名要见名知意 ,通常以Exception结尾,如OrderNotExistExceptionStockNotEnoughException

六、异常处理的最佳实践

掌握了异常的基础知识点后,更重要的是在实际开发中遵循最佳实践,让异常处理更规范、更高效:

  1. 避免捕获所有异常 :不要直接捕获Exception,会掩盖具体的异常类型,不利于问题排查,应捕获具体的异常类型;
  2. 不要忽略异常 :不要在catch块中只写e.printStackTrace(),甚至空的catch块,应根据业务场景做具体处理(如记录日志、提示用户、重试操作);
  3. 及时释放资源 :打开的 IO 流、数据库连接、网络连接等资源,必须在finally块中释放,或使用 Java7 的try-with-resources自动释放;
  4. 异常信息要精准 :抛出异常时,填写清晰的异常原因(如throw new NullPointerException("用户信息对象为null,无法获取用户ID")),便于排查问题;
  5. 子类方法抛出异常范围不超过父类:继承父类并重写方法时,子类方法抛出的异常类型不能是父类方法异常的父类,也不能抛出更多的受检查异常;
  6. 合理选择自定义异常的父类 :核心业务异常建议继承Exception,强制调用者处理;非核心异常建议继承RuntimeException,简化代码;
  7. 使用日志框架记录异常 :实际开发中,不要使用e.printStackTrace(),应使用 SLF4J/Logback 等日志框架记录异常(可记录异常级别、调用栈、业务上下文),便于线上问题排查。

七、总结

Java 异常处理是保证程序健壮性的核心,其核心是事后处理 的编程思想,通过throwthrowstrycatchfinally五个关键字实现异常的抛出、声明、捕获和处理。

本文从异常的概念出发,理清了ThrowableErrorException的继承关系,区分了编译时异常和运行时异常;然后详细讲解了异常处理的核心方式和执行流程;最后通过实战实现了贴合业务的自定义异常,并给出了开发中的最佳实践。

掌握异常处理的关键,不仅是记住语法和规则,更重要的是结合业务场景选择合适的处理方式:让程序在发生异常时,既能精准定位问题,又能优雅地处理异常,保证程序的正常运行。希望本文能让你对 Java 异常处理有更全面、更深入的理解,在实际开发中玩转异常体系!

相关推荐
御形封灵2 小时前
基于canvas的路网编辑交互
开发语言·javascript·交互
xifangge20252 小时前
Python 爬虫实战:爬取豆瓣电影 Top250 数据并进行可视化分析
开发语言·爬虫·python
SunnyDays10112 小时前
C# 实战:快速查找并高亮 Word 文档中的文字(普通查找 + 正则表达式)
开发语言·c#
standovon2 小时前
SQL SERVER 登陆错误:18456
java
大傻^2 小时前
Spring AI Alibaba 文档智能处理:PDF、Markdown知识入库全链路
java·人工智能·spring·pdf·知识图谱·springai·springaialibaba
kaoshi100app2 小时前
本周,河南二建报名公布!
开发语言·人工智能·职场和发展·学习方法
421!2 小时前
ESP32学习笔记之GPIO
开发语言·笔记·单片机·嵌入式硬件·学习·算法·fpga开发
恼书:-(空寄2 小时前
拦截器获取不到 POST 请求 JSON 结构体参数(完整解决方案)
java·spring boot·spring·servlet
problc2 小时前
在 OpenClaw 里一句话记账:消费说出来,账单自动进乖猫记账 App
开发语言·python