当前位置: 首页 > news >正文

Java基础语言进阶学习——4,Java异常体系和自定义异常

学习目标:深入理解Java异常体系和自定义异常


目录

学习目标:深入理解Java异常体系和自定义异常

一、异常体系的基本概念

1. 什么是异常?

2. Java异常体系结构

二、异常分类详解

1. 受检异常 (Checked Exception)

2. 非受检异常 (Unchecked Exception)

三、异常处理机制

1.核心概念区别

2.详细使用场景

a. try-catch-finally 使用场景

b. throws 使用场景

3. try-catch-finally 结构

4. throws 声明

5.总结

四、自定义异常

1. 为什么要自定义异常?

2. 自定义异常的实现方式

方式一:继承Exception(受检异常)

方式二:继承RuntimeException(非受检异常)

五、完整实战案例

用户服务系统异常处理

六、最佳实践和注意事项

1. 自定义异常设计原则

2. 异常处理最佳实践

七、总结

1.关键要点:

2.选择继承Exception还是RuntimeException?

注:此文章适合有一定Java基础的人群,有一些代码阅读量!


一、异常体系的基本概念

1. 什么是异常?

通俗理解:异常就是程序运行过程中出现的"意外情况",比如:

  • 读取文件时文件不存在

  • 网络连接突然断开

  • 数组访问越界

  • 数学运算除数为0

2. Java异常体系结构

Throwable (所有错误和异常的父类)
    ├── Error (系统级错误,程序无法处理)
    │     ├── OutOfMemoryError
    │     ├── StackOverflowError
    │     └── ...
    └── Exception (程序可以处理的异常)
          ├── RuntimeException (运行时异常,非受检异常)
          │     ├── NullPointerException
          │     ├── ArrayIndexOutOfBoundsException
          │     └── ...
          └── 其他Exception (受检异常)
                ├── IOException
                ├── SQLException
                └── ...

二、异常分类详解

1. 受检异常 (Checked Exception)

  • 核心特点:编译器强制处理(不处理无法编译)

  • 产生场景:可预见的、调用者应处理的业务可恢复错误
  • 常见类型:IOException、SQLException等

  • 处理方式:try-catch或throws声明(必须捕获或声明抛出)

2. 非受检异常 (Unchecked Exception)

  • 特点:RuntimeException及其子类,编译器不强制处理

  • 产生场景
    1. 代码缺陷(空指针、数组越界)
    2. 业务规则违例(参数非法、状态冲突)
    3. 不可控外部因素(用户输入错误、第三方库故障)
  • 常见类型:NullPointerException、IllegalArgumentException等

  • 处理原则
               1.基础框架层统一捕获(如Spring @ControllerAdvice)
                2.业务层可不处理(需确保全局兜底)

三、异常处理机制

1.核心概念区别

特性try-catch-finallythrows
作用在当前方法内部处理异常将异常抛给调用者处理
位置方法体内方法声明处
责任自己处理异常让别人处理异常
控制流异常被捕获,程序可以继续执行异常抛出,当前方法立即结束

2.详细使用场景

a. try-catch-finally 使用场景

适用情况:当你知道如何处理异常,并且希望程序能够继续执行时。

b. throws 使用场景

适用情况:当你不知道如何处理异常,或者异常应该由调用者决定如何处理时。

3. try-catch-finally 结构

public class ExceptionDemo {public static void main(String[] args) {try {// 可能抛出异常的代码int result = divide(10, 0);System.out.println("结果: " + result);} catch (ArithmeticException e) {// 捕获特定异常System.out.println("捕获到算术异常: " + e.getMessage());} catch (Exception e) {// 捕获其他异常System.out.println("捕获到其他异常: " + e.getMessage());} finally {// 无论是否发生异常都会执行System.out.println("finally块执行完成");}}public static int divide(int a, int b) {return a / b; // 可能抛出ArithmeticException}
}

4. throws 声明

public class ThrowsDemo {// 在方法声明中使用throws抛出异常public static void readFile(String filename) throws IOException {FileInputStream file = new FileInputStream(filename);// 文件操作...file.close();}public static void main(String[] args) {try {readFile("test.txt");} catch (IOException e) {System.out.println("文件读取失败: " + e.getMessage());}}
}

5.总结

记住这个简单的原则:

  • try-catch-finally:"我来处理这个麻烦"

  • throws:"这个麻烦交给你来处理"

在实际开发中,通常的做法是:

  • 底层技术层(DAO):多用throws

  • 业务逻辑层(Service):混合使用,转换异常类型

  • 表现层(Controller):多用try-catch,进行最终处理

四、自定义异常

1. 为什么要自定义异常?

  • 业务需求:Java内置异常无法满足特定业务场景

  • 明确语义:让异常名称更符合业务逻辑

  • 统一处理:便于对特定业务异常进行统一管理

2. 自定义异常的实现方式

方式一:继承Exception(受检异常)
/*** 自定义业务异常 - 受检异常* 用于表示用户相关的业务异常*/
public class UserNotFoundException extends Exception {private String userId;// 无参构造public UserNotFoundException() {super("用户不存在");}// 带消息的构造public UserNotFoundException(String message) {super(message);}// 带消息和用户ID的构造public UserNotFoundException(String message, String userId) {super(message);this.userId = userId;}// 带消息和原因的构造public UserNotFoundException(String message, Throwable cause) {super(message, cause);}public String getUserId() {return userId;}@Overridepublic String getMessage() {if (userId != null) {return super.getMessage() + " [用户ID: " + userId + "]";}return super.getMessage();}
}

方式二:继承RuntimeException(非受检异常)
/*** 自定义业务异常 - 非受检异常* 用于表示参数校验失败等运行时异常*/
public class InvalidParameterException extends RuntimeException {private String fieldName;private Object invalidValue;public InvalidParameterException(String fieldName, Object invalidValue) {super("参数 " + fieldName + " 的值 " + invalidValue + " 无效");this.fieldName = fieldName;this.invalidValue = invalidValue;}public InvalidParameterException(String message, String fieldName, Object invalidValue) {super(message);this.fieldName = fieldName;this.invalidValue = invalidValue;}// getter方法public String getFieldName() {return fieldName;}public Object getInvalidValue() {return invalidValue;}
}

五、完整实战案例

用户服务系统异常处理

import java.util.HashMap;
import java.util.Map;// 用户类
class User {private String id;private String name;private int age;public User(String id, String name, int age) {this.id = id;this.name = name;this.age = age;}// getter方法...public String getId() { return id; }public String getName() { return name; }public int getAge() { return age; }
}
// 用户服务类
class UserService {private Map<String, User> userDatabase = new HashMap<>();// 添加用户public void addUser(User user) throws InvalidUserException {// 参数校验if (user == null) {throw new InvalidUserException("用户对象不能为null");}if (user.getId() == null || user.getId().trim().isEmpty()) {throw new InvalidUserException("用户ID不能为空", "id", user.getId());}if (user.getAge() < 0 || user.getAge() > 150) {throw new InvalidUserException("年龄必须在0-150之间", "age", user.getAge());}// 检查用户是否已存在if (userDatabase.containsKey(user.getId())) {throw new UserAlreadyExistsException("用户已存在: " + user.getId(), user.getId());}userDatabase.put(user.getId(), user);System.out.println("用户添加成功: " + user.getName());}// 查找用户public User findUser(String userId) throws UserNotFoundException {User user = userDatabase.get(userId);if (user == null) {throw new UserNotFoundException("用户不存在", userId);}return user;}// 删除用户public void deleteUser(String userId) throws UserNotFoundException {if (!userDatabase.containsKey(userId)) {throw new UserNotFoundException("无法删除不存在的用户", userId);}userDatabase.remove(userId);System.out.println("用户删除成功: " + userId);}
}
// 自定义异常类
class InvalidUserException extends RuntimeException {private String fieldName;private Object invalidValue;public InvalidUserException(String message) {super(message);}public InvalidUserException(String message, String fieldName, Object invalidValue) {super(message);this.fieldName = fieldName;this.invalidValue = invalidValue;}public String getFieldName() { return fieldName; }public Object getInvalidValue() { return invalidValue; }
}class UserAlreadyExistsException extends RuntimeException {private String userId;public UserAlreadyExistsException(String message, String userId) {super(message);this.userId = userId;}public String getUserId() { return userId; }
}
// 测试类
public class CustomExceptionDemo {public static void main(String[] args) {UserService userService = new UserService();// 测试正常流程try {User user1 = new User("001", "张三", 25);userService.addUser(user1);User foundUser = userService.findUser("001");System.out.println("找到用户: " + foundUser.getName());} catch (InvalidUserException | UserNotFoundException e) {System.out.println("业务异常: " + e.getMessage());}// 测试异常情况System.out.println("\n=== 测试异常情况 ===");// 1. 测试无效用户try {User invalidUser = new User("", "李四", 25);userService.addUser(invalidUser);} catch (InvalidUserException e) {System.out.println("捕获到无效用户异常: " + e.getMessage());if (e.getFieldName() != null) {System.out.println("问题字段: " + e.getFieldName() + ", 无效值: " + e.getInvalidValue());}}// 2. 测试重复用户try {User user2 = new User("001", "王五", 30); // 与之前ID重复userService.addUser(user2);} catch (UserAlreadyExistsException e) {System.out.println("捕获到用户已存在异常: " + e.getMessage());}// 3. 测试查找不存在的用户try {userService.findUser("999");} catch (UserNotFoundException e) {System.out.println("捕获到用户不存在异常: " + e.getMessage());System.out.println("查找的用户ID: " + e.getUserId());}// 4. 测试年龄异常try {User ageUser = new User("003", "赵六", -5);userService.addUser(ageUser);} catch (InvalidUserException e) {System.out.println("捕获到年龄异常: " + e.getMessage());}}
}

六、最佳实践和注意事项

1. 自定义异常设计原则

  • 命名规范:异常名以"Exception"结尾,清晰表达异常含义

  • 提供多个构造方法:支持不同使用场景

  • 包含有用信息:提供有助于问题定位的额外信息

  • 保持不可变性:异常对象应该是不可变的

2. 异常处理最佳实践

public class ExceptionBestPractice {// 好的做法:提供详细的错误信息public void goodPractice(String input) {if (input == null || input.trim().isEmpty()) {throw new IllegalArgumentException("输入参数不能为空或空白字符串");}// 业务逻辑...}// 不好的做法:过于简单的错误信息public void badPractice(String input) {if (input == null) {throw new IllegalArgumentException("参数错误"); // 信息不明确}}// 好的做法:异常链保持public void processFile(String filename) {try {// 文件处理逻辑} catch (IOException e) {// 保留原始异常信息throw new BusinessException("文件处理失败: " + filename, e);}}// 不要忽略异常public void dontIgnoreException() {try {// 某些操作} catch (Exception e) {// 不好的做法:空的catch块// 好的做法:至少记录日志或采取恢复措施System.err.println("发生异常: " + e.getMessage());// 或者记录日志: logger.error("处理失败", e);}}
}

七、总结

1.关键要点:

  1. 异常分类:理解受检异常和非受检异常的区别

  2. 处理机制:掌握try-catch-finally和throws的使用

  3. 自定义异常:根据业务需求创建合适的异常类

  4. 最佳实践:提供清晰的错误信息,不要忽略异常

2.选择继承Exception还是RuntimeException?

  • 继承Exception(受检异常)当且仅当:

    • 调用者可具体处理恢复(如重试上传)
    • 低频且严重的错误
      反例: 登录密码错误(高频场景)不应设计为受检异常
  • 继承RuntimeException(非受检异常)的条件:

    • 调用者无法干预修复(如第三方服务崩溃)
    • 业务高频触发的规则违例(如库存不足)
    • 框架设计考量(避免污染Lambda表达式)

http://www.dtcms.com/a/574061.html

相关文章:

  • junit使用
  • 电商网站开发需要掌握哪些知识技能做黑彩网站会怎样处罚
  • 自制51单片机开发板:STC89C52RC最小系统+LCD1602A屏幕
  • 崇州网站制作网站下载软件
  • 实现El-table 每行后面加验证
  • 淘宝网站制作广州公共资源交易
  • 在IAR Embedded Workbench for Arm中开发和调试Infineon MOTIX™ MCU
  • 贵阳市花溪区建设局网站商河做网站公司
  • JDK Maven Tomcat部分配置细节(自用)
  • 网站开发文档步骤应该怎么写开网站设计公司多少钱
  • 城市超级智能体破解落地难题,联想开启智慧城市4.0时代
  • 小型企业门户网站源码电商平台开发系统软件平台
  • 【16】Selenium+Python 接管已打开谷歌浏览器
  • 公司网站导航栏是什么天堂 在线地址8
  • Lay-Vue-Super前后端分离的通用后台管理项目
  • 网站虚拟主机建设在线房屋设计免费图
  • Give LLMs a Security Course 论文结构速览
  • 经典的 VLM 攻击汇总
  • 山东网站方案秦皇岛网站建设找汉狮
  • 基于电鱼 AI 工控机的智慧工地视频智能分析方案——边缘端AI检测,实现无人值守下的实时安全预警
  • phpstudy 无法启动mysql 但命令可以启动mysql
  • 【经典游戏】保姆级:Unity3D飞机大战(含资源包、完整项目)
  • Guava Cache淘汰算法
  • 门户网站类是什么意思怎么给自己做个网站吗
  • 小朋友做安全教育的网站慈溪做网站什么价
  • 设计一个网站的步骤深汕特别合作区包括哪些地方
  • 2.5 HuggingFace Transformers 库实战
  • 宿州建设企业网站公司做网站的有哪些学校
  • 网络通信的奥秘:HTTP详解 (七)
  • 福建网站建设科技有限公司那些网站做的非常好看的