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

Java 异常 - 基础

前言

从生活类比开始,逐步过渡到 Java 代码、类型体系、异常处理规则,最后再简单提底层原理


一、从生活例子理解“异常”

场景:你写了一个程序,让用户输入两个整数,然后计算除法。

请输入被除数:10 请输入除数:0

计算10 / 0在数学中无意义,在 Java 里会抛出一个异常ArithmeticException)。

异常就像生活中的“意外状况”:

  • 你计划“去超市买东西 → 结账 → 回家”。
  • 中途发现忘带钱包→ 这是异常。
  • 你需要处理它:回家取钱 / 找朋友借 / 取消购物。

程序也是如此:异常是意料之外的事件,打断正常流程,我们需要捕获并处理,或向上报告


二、Java 中的第一个异常处理程序

publicclassDivideDemo{publicstaticvoidmain(String[]args){inta=10;intb=0;try{intc=a/b;// 可能抛出异常System.out.println("结果是:"+c);}catch(ArithmeticExceptione){System.out.println("出错啦!除数不能为0");}System.out.println("程序继续运行...");}}

输出

出错啦!除数不能为0 程序继续运行...

关键点

  • try块:放“可能出错的代码”。
  • catch块:捕获特定类型的异常,执行“补救代码”。
  • 即使发生异常,程序没有崩溃,而是继续执行后面的语句。

三、异常的核心概念

1. 异常的“抛出”与“捕获”

  • 抛出:用throw关键字(或者 JVM 自动抛出)产生一个异常对象。
  • 捕获:用try-catch接住这个异常对象,执行处理逻辑。

2. 异常对象

每个异常都是一个对象,类型是java.lang.Throwable或其子类。
这个对象里记录了:

  • 异常类型(如除零、空指针)
  • 错误信息(字符串)
  • 调用栈(哪个类、哪个方法、哪一行引发的异常)

可以用e.printStackTrace()打印调用栈,帮助调试。


四、异常的类型体系

Throwable ← 所有异常/错误的根类 / \ / \ Error Exception / \ / \ RuntimeException 其他Exception(如IOException)

1.Error:表示严重问题,程序无法处理

  • 例如:内存耗尽(OutOfMemoryError)、栈溢出(StackOverflowError)。
  • 一般不需要捕获,程序也基本无法恢复。

2.Exception:表示程序可以处理的异常

  • RuntimeException(运行时异常):编程错误导致,例如:
    • NullPointerException(空指针)
    • ArrayIndexOutOfBoundsException(数组越界)
    • ArithmeticException(除零)
    • 编译器不强制捕获,但你可以选择捕获。
  • Checked Exception(受检异常):外部因素导致,例如:
    • IOException(文件不存在、网络错误)
    • SQLException(数据库错误)
    • 编译器强制要求处理:要么try-catch,要么在方法上用throws声明。

简单记:RuntimeException写代码时疏忽导致的;Checked Exception 是外部环境问题(如文件找不到)。


五、如何处理受检异常(Checked Exception)

假设读取一个文件,文件可能不存在:

importjava.io.*;publicclassReadFile{publicstaticvoidmain(String[]args){try{FileReaderfr=newFileReader("test.txt");}catch(FileNotFoundExceptione){System.out.println("文件不存在,请检查路径");}}}

如果不处理,直接写FileReader fr = new FileReader("test.txt");,编译器会报错:

Unhandled exception: java.io.FileNotFoundException

两种合法做法:

  1. try-catch(如上所示)—— 自己处理。
  2. throws—— 向上抛出,交给调用者处理。
publicstaticvoidreadFile()throwsFileNotFoundException{FileReaderfr=newFileReader("test.txt");}

六、finally:不管有没有异常,都要执行的代码

finally常用于释放资源(关闭文件、数据库连接等)。

FileReaderfr=null;try{fr=newFileReader("test.txt");// 读取数据...}catch(IOExceptione){e.printStackTrace();}finally{if(fr!=null){try{fr.close();}catch(IOExceptione){e.printStackTrace();}}}

特点

  • 无论try中是否发生异常,finally都会执行(除非 JVM 崩溃或System.exit(0))。
  • 如果catch中有returnfinally仍会在return之前执行。

小技巧:Java 7 引入了try-with-resources,可以自动关闭实现AutoCloseable的资源,代码更简洁。


七、throwthrows的区别

关键字位置作用
throws方法声明后面表示这个方法可能会抛出某种异常,调用者必须处理
throw方法体内部手动抛出一个异常对象
publicstaticvoidcheckAge(intage)throwsIllegalArgumentException{if(age<0){thrownewIllegalArgumentException("年龄不能为负数");}}

八、自定义异常

你可以创建自己的异常类,通常继承Exception(受检)或RuntimeException(非受检)。

// 自定义受检异常classMyBusinessExceptionextendsException{publicMyBusinessException(Stringmessage){super(message);}}// 使用publicvoiddoSomething()throwsMyBusinessException{if(someError){thrownewMyBusinessException("业务出错啦");}}

九、异常处理的最佳实践

  1. 不要用异常代替正常的条件判断(比如用try-catch判断数组越界 → 性能差且代码混乱)。
  2. 捕获异常要具体:不要总写catch (Exception e),应捕获IOExceptionNullPointerException等。
  3. 不要吞噬异常catch里至少打日志e.printStackTrace(),别空着。
  4. finally 中不要 return,否则会覆盖 try/catch 中的异常。
  5. 抛出的异常要有意义throw new IllegalArgumentException("参数不能为 null")

十、异常的执行流程

这一节简单讲底层,不涉及字节码细节,只建立感性认识。

1. 异常发生时,JVM 做了什么?

  • 停止当前方法的正常执行。
  • 沿着方法调用栈往回找,看哪个catch能处理这个异常。
  • 如果找到,就跳转到对应的catch块执行。
  • 如果一直没找到,程序会终止,并打印异常信息(调用栈)。

2. 为什么捕获异常有性能开销?

  • 创建异常对象时,JVM 要记录整个调用栈(哪个方法调了哪个方法),这需要时间。
  • 因此,只在真正异常时使用,不要用异常做普通的循环控制。

3. 受检异常为什么是“编译时检查”?

  • 编译器会扫描代码,如果某个方法可能抛出受检异常却没有被捕获或声明,就报错。这是 Java 的设计理念:强制程序员考虑错误处理。

十一、总结(一张图记住全部)

程序运行 | v 执行 try 块 | +-- 正常 → 跳过 catch → 执行 finally → 继续 | +-- 发生异常 → 创建异常对象 → 查找匹配的 catch | +-- 找到 → 执行 catch → 执行 finally → 继续 | +-- 没找到 → 执行 finally → 异常向上抛给调用者

核心三问

  1. 异常是什么? → 意外事件,打断正常流程。
  2. 怎么处理? →try-catch-finallythrows
  3. 异常分几类? →Error(不处理)、RuntimeException(可选处理)、Checked Exception(必须处理)。

http://www.zskr.cn/news/1427321.html

相关文章:

  • 从屏幕涂鸦到专业演示:ppInk如何重新定义你的数字表达方式
  • MyTV-Android:老旧电视重获新生的终极直播解决方案
  • 如何测试一个 Agent 智能体?工具调用准确率与任务规划能力的评估
  • nAFDM技术:提升高速移动通信频谱效率的创新方案
  • 5分钟快速掌握SMUDebugTool:免费开源AMD Ryzen硬件调试终极指南
  • Claude Code 深度使用40小时复盘:把AI当成你的复利账户
  • 2026年VMware替代趋势观察:国产虚拟化软件云宏CNware的平滑迁移方案
  • W4A8量化技术与LiquidGEMM优化实践
  • Claude商业分析报告失效的最后72小时:当客户流失预测置信度骤降超18%,这4个信号必须立刻干预(实时监控SOP已上线)
  • Lovable区块链平台性能瓶颈突破:5个被90%团队忽略的共识层优化关键点
  • 终极PUBG压枪宏配置指南:5步实现完美无后坐力射击
  • 给程序员的气象学:用代码思维图解大气环流三圈模型(哈德来/费雷尔/极地环流)
  • 打造个人云游戏服务器:Sunshine终极配置实战指南
  • AI 系统的“黄金数据集”:为什么构建高质量的评测集比写自动化还难?
  • Claude Code安装+88api中转配置一篇搞定(Windows)
  • 兰州黄金上门回收平台对比2026 - 黄金回收
  • 智博会上的国产芯:重新定义 Token 价值链路
  • 从Dropout到残差连接:实战中如何为你的基因预测模型选择正则化与防梯度消失策略
  • 其利天下圆满完成第二十届深圳国际金融博览会参展之行
  • EliSpot 技术:疫苗研发不可或缺的核心工具
  • 基于边缘计算与Bun运行时构建高性能新闻聚合系统架构实践
  • 北京金发钹祥金属材料贸易:靠谱的北京不锈钢焊接公司 - LYL仔仔
  • Kubernetes 控制器(Controller)详解【20260530】001篇
  • 2026年4月中封袋生产商推荐,聚酯尼龙袋/包装袋/中封袋/八边封包装袋/三边封包装袋,中封袋订做厂家口碑推荐 - 品牌推荐师
  • Python小红书数据采集终极指南:xhs库完整使用教程与实战应用
  • OEXN平台:信息披露与运营规范性的评测参考
  • 如何高效抓取抖音直播间弹幕数据:DouyinLiveWebFetcher完整解析
  • Kubernetes 控制器(Controller)详解【20260530】002篇
  • 2026 西安黄金回收全解析:行情、避坑与正规渠道 - 奢侈品回收测评
  • 基于Arduino与MLX90614的红外测温仪DIY全攻略