Java 异常处理全解析:从基础到自定义异常的实战指南

news2025/4/28 9:30:35

Java 异常处理全解析:从基础到自定义异常的实战指南

一、Java 异常体系:Error 与 Exception 的本质区别

1. 异常体系核心架构

Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类。

在Java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception

Java 异常体系基于Throwable类,分为两大分支:

Throwable
├─ Error(错误)
│  └─ 例:OutOfMemoryErrorStackOverflowError
└─ Exception(异常)
   ├─ Checked Exception(编译时异常)
   │  └─ 例:IOExceptionSQLException
   └─ Unchecked Exception(运行时异常)
      └─ 例:NullPointerExceptionArrayIndexOutOfBoundsException

在这里插入图片描述

2.什么是异常以及异常的简单分类

  • 异常指程序运行中出现的不期而至的各种状况,如:文件找不到、网络连接失败、非法参数等。
  • 异常发生在程序运行期间,它影响了正常的程序执行流程。

要理解java异常处理是如何工作的,你需要掌握以下三种类型的异常Exception

  1. 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
  2. 运行时异常:运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
  3. 错误Error: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

3. Error vs Exception

Error和Exception的区别:Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程;Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。

维度ErrorException
本质JVM 底层错误,不可恢复程序运行中的异常情况
处理方式无法捕获,需重启 JVM可捕获处理或声明抛出
典型场景内存溢出、类加载失败空指针、数组越界、用户输入错误

4. Checked vs Unchecked 异常

  • Checked 异常

    • 必须显式处理(捕获或声明抛出)
    • 示例:文件读取时的FileNotFoundException
    try {
        FileReader reader = new FileReader("file.txt");
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    
  • Unchecked 异常

    • 无需强制处理(运行时检查)
    • 示例:参数校验失败的IllegalArgumentException
    public void checkAge(int age) {
        if (age < 0) {
            throw new IllegalArgumentException("年龄不能为负数");
        }
    }
    

二、异常处理核心机制:捕获与抛出

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

try {
    // 可能抛出异常的代码
    int result = 10 / 0; // 抛出ArithmeticException
} catch (ArithmeticException e) { // 捕获具体异常
    System.out.println("错误原因:" + e.getMessage()); // 输出:/ by zero
    e.printStackTrace(); // 打印堆栈跟踪信息
} catch (Exception e) { // 父类异常捕获(需放在最后)
    // 通用异常处理
} finally {
    // 可选:无论是否异常都会执行(常用于资源释放)
    System.out.println("执行finally块");
}

2. 异常抛出关键字

throw(方法内抛出异常实例)
public static int divide(int a, int b) {
    if (b == 0) {
        throw new ArithmeticException("除数不能为0"); // 主动抛出异常
    }
    return a / b;
}
throws(方法声明抛出异常)
public static void readFile(String path) throws FileNotFoundException {
    FileReader reader = new FileReader(path); // 声明抛出Checked异常
}

3. 异常处理顺序原则

  • 子类异常优先:具体异常(如FileNotFoundException)需写在父类异常(如IOException)之前
  • finally 的绝对性:即使 try 块中有return,finally 仍会执行(但返回值会被缓存)

4.本节狂神说笔记

package com.exception;

public class Test {
    public static void main(String[] args) {
        int a = 10;
        int b = 0;

        //假设要捕获多个异常: 从小到大!

        try {//try监控区域
            System.out.println(a/b);
        } catch (Error e) {//catch(想要捕获的异常类型!)捕获异常
            System.out.println("Error");
        } catch (Exception e) {
            System.out.println("Exception");
        } catch (Throwable e) {
            System.out.println("Throwable");
        } finally {//处理善后工作
            System.out.println("finally");
        }

        finally 可以不要finally, 假设I0,资源,关闭!
    }
    public void a(){
        b();
    }
    public void b(){
        a();
    }
}
package com.exception;

public class Test2 {
    public static void main(String[] args) {
        int a = 1;
        int b = 0;

        //Ctrl Alt + T
        try {
            System.out.println(a/b);
        } catch (Exception e) {
            e.printStackTrace();//打印错误的栈信息
        } finally {
        }
    }
}
package com.exception;

public class Test1 {
    public static void main(String[] args) {
        try {
            new Test1().test(1,0);
        } catch (ArithmeticException e) {
            e.printStackTrace();
        }
    }

    //假设这个方法中,处理不了这个异常。方法上抛出异常
    public void test(int a,int b) throws ArithmeticException{
        if(b == 0){//throw  throws
            throw new ArithmeticException();//主动的抛出异常,一般在方法中使用
        }
    }
}

三、自定义异常:打造业务专属错误体系

使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可。

1. 自定义异常类步骤

  1. 创建自定义异常类。
  2. 在方法中通过throw关键字抛出异常对象。
  3. 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
  4. 在出现异常方法的调用者中捕获并处理异常。
步骤 1:继承 Exception 或 RuntimeException
// Checked异常(需显式处理)
public class UserAgeException extends Exception {
    public UserAgeException(String message) {
        super(message); // 调用父类构造器
    }
}

// Unchecked异常(运行时异常)
public class InvalidInputException extends RuntimeException {
    public InvalidInputException(String message) {
        super(message);
    }
}
步骤 2:在业务逻辑中抛出
public void validateUser(int age) throws UserAgeException {
    if (age < 18) {
        throw new UserAgeException("用户年龄必须≥18岁"); // 抛出自定义Checked异常
    }
}

2. 异常处理最佳实践

(1)异常信息规范
  • 包含足够上下文:"用户ID为" + userId + "的账户不存在"
  • 避免裸露捕获Exception:应捕获具体异常类型
(2)资源释放最佳实践
// JDK 7+ 自动资源管理(替代finally)
try (FileReader reader = new FileReader("file.txt")) {
    // 自动关闭资源(无需显式finally)
} catch (IOException e) {
    // 处理文件读取异常
}
(3)异常链使用
try {
    // 业务逻辑
} catch (ServiceException e) {
    throw new ControllerException("接口调用失败", e); // 包装异常链
}

3.实际应用中的经验总结

  • 处理运行时异常时,采用逻辑去合理规避同时辅助 try-catch 处理
  • 在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
  • 对于不确定的代码,也可以加上 try-catch,处理潜在的异常
  • 尽量去处理异常,切忌只是简单地调用 printStackTrace()去打印输出
  • 具体如何处理异常,要根据不同的业务需求和异常类型去决定
  • 尽量添加finally语句块去释放占用的资源

四、常见异常处理错误与解决方案

1. 空指针异常(NPE)

错误示例

String str = null;
int length = str.length(); // 抛出NullPointerException

解决方案

if (str != null) {
    int length = str.length();
} else {
    throw new IllegalArgumentException("字符串不可为null");
}

2. 未处理 Checked 异常

错误示例

public void readFile() {
    FileReader reader = new FileReader("file.txt"); // 编译错误:未处理IOException
}

解决方案

// 方案1:捕获处理
try { /* ... */ } catch (IOException e) { /* ... */ }

// 方案2:声明抛出
public void readFile() throws IOException { /* ... */ }

3. finally 中的 return 陷阱

错误示例

public static int testFinally() {
    try {
        return 1;
    } finally {
        return 2; // 最终返回2,覆盖try中的return
    }
}

正确做法

public static int testFinally() {
    int result = 1;
    try {
        return result;
    } finally {
        result = 2; // 不建议在finally中使用return
    }
}

五、高频面试题解析

1. Error 和 Exception 的根本区别?

  • Error 是 JVM 内部错误(如内存溢出),无法通过代码处理,必须重启应用
  • Exception 是程序运行中的异常,分为 Checked(编译时检查)和 Unchecked(运行时异常)

2. throw 和 throws 的区别?

关键字作用使用位置参数类型
throw抛出异常实例方法体内部异常对象
throws声明方法可能抛出的异常类型方法签名异常类列表

3. finally 块一定会执行吗?

  • 正常情况下一定会执行(包括 return 前执行)
  • 唯一例外:JVM 提前终止(如System.exit(0)

4. 自定义异常应该继承哪个类?

  • 业务需要编译时检查:继承Exception
  • 运行时异常(如参数校验失败):继承RuntimeException

六、异常处理核心原则

  1. 具体捕获:优先捕获具体异常,避免使用宽泛的Exception
  2. 快速失败:在方法入口校验参数,尽早抛出异常
  3. 信息完整:异常信息需包含定位问题的关键数据(如用户 ID、时间戳)
  4. 资源管理:使用try-with-resources自动释放 IO、数据库连接等资源

七、总结:构建健壮的异常处理体系

通过合理运用 Java 异常处理机制,开发者可以:

  1. 清晰区分系统错误与业务异常
  2. 通过捕获特定异常实现精准的错误处理
  3. 利用自定义异常提升业务代码的可读性
    该继承哪个类?
  • 业务需要编译时检查:继承Exception
  • 运行时异常(如参数校验失败):继承RuntimeException

六、异常处理核心原则

  1. 具体捕获:优先捕获具体异常,避免使用宽泛的Exception
  2. 快速失败:在方法入口校验参数,尽早抛出异常
  3. 信息完整:异常信息需包含定位问题的关键数据(如用户 ID、时间戳)
  4. 资源管理:使用try-with-resources自动释放 IO、数据库连接等资源

七、总结:构建健壮的异常处理体系

通过合理运用 Java 异常处理机制,开发者可以:

  1. 清晰区分系统错误与业务异常
  2. 通过捕获特定异常实现精准的错误处理
  3. 利用自定义异常提升业务代码的可读性
  4. 结合 finally 和 try-with-resources 确保资源安全释放

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2343831.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开源AI智能名片链动2+1模式S2B2C商城小程序源码赋能下的社交电商创业者技能跃迁与价值重构

摘要&#xff1a;在移动互联网深度重构商业生态的背景下&#xff0c;社交电商创业者面临流量成本攀升、用户粘性不足、供应链协同低效等核心痛点。本文以“开源AI智能名片链动21模式S2B2C商城小程序源码”技术体系为研究对象&#xff0c;通过分析其技术架构、商业逻辑及实战案例…

WSL 中 nvidia-smi: command not found的解决办法

前言 在使用基于 Linux 的 Windows 子系统&#xff08;WSL&#xff09;时&#xff0c;当我们执行某些操作后&#xff0c;可能会遇到输入 nvidia-smi 命令却无法被系统识别的情况。 例如&#xff0c;在终端中输入nvidia-smi 后&#xff0c;系统返回提示 -bash: nvidia-smi: co…

FPGA前瞻篇-组合逻辑电路设计-多路复用器

多路选择器&#xff08;MUX&#xff09;简介 基本概念 多路选择器&#xff08;MUX&#xff0c;Multiplexer&#xff09;是一种多输入、单输出的组合逻辑电路。 它通过选择控制信号&#xff0c;在多个输入信号中选择一个连接到输出端。 可以理解为一个多路数字开关。 &…

【Castle-X机器人】五、物联网模块配置与调试

持续更新。。。。。。。。。。。。。。。 【Castle-X机器人】五、物联网模块配置与调试 五、物联网模块配置与调试5.1 物联网模块调试物联网模块测试:控制物联网模块:物联网模块话题五、物联网模块配置与调试 5.1 物联网模块调试 调试前需确保Castle-x与mqtt主机服务器处于同…

20250426在ubuntu20.04.2系统上打包NanoPi NEO开发板的FriendlyCore系统刷机eMMC的固件

20250426在ubuntu20.04.2系统上打包NanoPi NEO开发板的FriendlyCore系统刷机eMMC的固件 2025/4/26 21:30 缘起&#xff1a;使用NanoPi NEO开发板&#xff0c;编译FriendlyCore系统&#xff0c;打包eMMC固件的时候报错。 1、在ubuntu14.04下git clone异常该如何处理呢&#xff…

JAVA---字符串

ctrlN 搜索界面&#xff08;idea&#xff09; API和API帮助文档 API &#xff1a; 应用程序编程接口&#xff08;换句话说&#xff0c;就是别人已经写好了&#xff0c;我们不需要再编写&#xff0c;直接使用即可&#xff09; Java API &#xff1a;就是JDK中提供的各种功能…

MacOS 10.15上能跑大语言模型吗?

MacOS 10.15上能跑大语言模型吗&#xff1f; 下载安装Ollama运行大语言模型引申出的问题 MacOS 10.15.7&#xff08;发布于2020年9月&#xff09;作为已经发布了将近5年的系统版本能够运行当今流行的大语言模型吗&#xff1f;这篇文章简要介绍了在MacOS 10.15上通过Ollama运行d…

AI Agent开发第37课-DeepSeek的多模态版JanusPro-7B本地安装

开篇 搜遍Janus Pro git issues、谷哥、国内网络,教程全都是错的。因此还是决定写一本全网唯一正确的教程。 目前网上的教程包括外网的教程都是“缺斤少量”,按照那些教程操作下来不是装不起来,就是装起来只能CPU运行,或者运行起来了Janus的Web前端老是转啊转不出内容。 …

神经网络笔记 - 感知机

一 感知机是什么 感知机&#xff08;Perceptron&#xff09;是一种接收输入信号并输出结果的算法。 它根据输入与权重的加权和是否超过某个阈值&#xff08;threshold&#xff09;&#xff0c;来判断输出0还是1。 二.计算方式 感知机的基本公式如下&#xff1a; X1, X2 : …

阿里云基于本地知识库构建RAG应用 | 架构与场景

RAG&#xff08;检索增强生成&#xff0c;Retrieval-Augmented Generation&#xff09;是一种结合了检索和生成技术的框架&#xff0c;旨在通过外部知识库的检索来增强大语言模型&#xff08;LLM&#xff09;的生成能力。 其核心架构包括两个主要部分&#xff1a; 检索模块&a…

CSS简单实用的加载动画、骨架屏有效果图

效果图 .wxml <!-- 骨架屏 --> <view wx:for"{{skeleton}}" wx:key"index" class"container center" style"--w:{{item.w}}rpx;--h:{{item.h}}rpx" /> <!-- 加载 --> <view class"arco-loading center&quo…

3:QT联合HALCON编程—海康相机SDK二次程序开发

思路&#xff1a; 1.定义带UI界面的主函数类 1.1在主函数中包含其它所有类头文件&#xff0c;进行声明和实例化&#xff1b;使用相机时&#xff0c;是用公共相机的接口在某一个具体函数中去实例化具体的海康相机对象。 1.2设计界面&#xff1a;连接相机&#xff0c;单次采集&a…

【前后端分离项目】Vue+Springboot+MySQL

文章目录 1.安装 Node.js2.配置 Node.js 环境3.安装 Node.js 国内镜像4.创建 Vue 项目5.运行 Vue 项目6.访问 Vue 项目7.创建 Spring Boot 项目8.运行 Spring Boot 项目9.访问 Spring Boot 项目10.实现 Vue 与 Spring Boot 联动11.安装 axios12.编写请求13.调用函数请求接口14.…

数据结构和算法(八)--2-3查找树

目录 一、平衡树 1、2-3查找树 1.1、定义 1.2、查找 1.3、插入 1.3.1、向2-结点中插入新键 1.3.2、向一棵只含有一个3-结点的树中插入新键 1.3.3、向一个父结点为2-结点的3-结点中插入新键 1.3.4、向一个父结点为3-结点的3-结点中插入新键 1.3.5、分解根结点 1.4、2…

Unity-Shader详解-其二

前向渲染和延迟渲染 前向渲染和延迟渲染总的来说是我们的两种主要的渲染方式。 我们在Unity的Project Settings中的Graphic界面能够找到渲染队列的设定&#xff1a; 我们也可以在Main Camera这里进行设置&#xff1a; 那这里我们首先介绍一下两种渲染&#xff08;Forward R…

深入浅出理解并应用自然语言处理(NLP)中的 Transformer 模型

1 引言 随着信息技术的飞速发展&#xff0c;自然语言处理&#xff08;Natural Language Processing, NLP&#xff09;作为人工智能领域的一个重要分支&#xff0c;已经取得了长足的进步。从早期基于规则的方法到如今的深度学习技术&#xff0c;NLP 正在以前所未有的速度改变着我…

当自动驾驶遇上“安全驾校”:NVIDIA如何用技术给无人驾驶赋能?

自动驾驶技术的商业化落地&#xff0c;核心在于能否通过严苛的安全验证。国内的汽车企业其实也在做自动驾驶&#xff0c;但是吧&#xff0c;基本都在L2级别。换句话说就是在应急时刻内&#xff0c;还是需要人来辅助驾驶&#xff0c;AI驾驶只是决策层&#xff0c;并不能完全掌握…

【OSG学习笔记】Day 9: 状态集(StateSet)与渲染优化 —— 管理混合、深度测试、雾效等渲染状态

干货开始。_ 一、StateSet核心概念与作用 StateSet 是OSG(OpenSceneGraph)中管理渲染状态的核心类,用于封装 OpenGL 渲染状态(如混合、深度测试、雾效、材质、纹理、着色器等),并将这些状态应用于节点或几何体。 通过合理组织 StateSet,可实现: 渲染状态的高效复用:…

Operating System 实验七 Linux文件系统实验

实验目标: 使用dd命令创建磁盘镜像文件ext2.img并格式化为ext2文件系统,然后通过mount命令挂载到Linux主机文件系统。查看ext2文件系统的超级块的信息,以及数据块的数量、数据块的大小、inode个数、空闲数据块的数量等信息 在文件系统中创建文件xxxxx.txt(其中xxxxx为你的学…

linux中shell脚本的编程使用

linux中shell脚本的编程使用 1.shell的初步理解1.1 怎么理解shell1.2 shell命令 2.shell编程2.1 什么是shell编程2.2 C语言编程 和 shell编程的区别 3.编写和运行第一个shell脚本程序3.1 编写时需要注意以下几点&#xff1a;3.1.1 shell脚本没有main函数&#xff0c;没有头文件…