定义
异常(Exception),指在程序的运行过程中,发生了不正常的现象,阻止了程序的运行,称之为发生异常。
语法
try{// 这里放入可能出现异常的代码}catch(Exceptionex){// 1. 这里放入处理异常的代码,如果try代码出现异常,则会执行此处代码// 2. 若try中没有异常,则不会执行此处代码|------------------------||// 可以有多重catch ||// 会从上往下判断 ||// 只会执行其中一个 ||}catch(Exceptionex){||------------------------|}finally{// 此处放入使用要执行的代码,无论是否发生异常// 唯一的例外:遇到System.exit()时不会执行此处代码}异常分类
| 对比维度 | Error (错误) | Exception (异常) |
|---|---|---|
| 本质 | 不可恢复的严重系统级问题。 | 可恢复的程序运行时问题。 |
| 产生原因 | JVM层面的资源耗尽或系统崩溃,如内存溢出、栈溢出。 | 程序逻辑错误或外部环境因素,如文件不存在、空指针。 |
| 处理方式 | 不应被捕获。程序通常只能终止。 | 应该被捕获和处理,使程序能优雅地继续或退出。 |
| 常见示例 | OutOfMemoryError(内存溢出)StackOverflowError(栈溢出) | NullPointerException(空指针)IOException(IO异常) |
throw 和 throws的区别
| 位置 | 内容 | 作用 | |
|---|---|---|---|
| throw | 方法内部 | throw + 异常对象 | 制造异常,抛出异常 |
| throws | 方法的签名处、声明处 | throws + 异常类型 | 告诉方法的调用者,这个方法可能出现的异常 |
异常分类:检查型异常 vs 非检查型异常
| 对比维度 | 检查型异常 (Checked Exception) | 非检查型异常 (Unchecked Exception / RuntimeException) |
|---|---|---|
| 继承关系 | Exception的子类(RuntimeException除外) | RuntimeException的子类 |
| 编译器要求 | 强制处理 (try-catch或throws) | 不强制处理 |
| 产生原因 | 外部环境因素(开发者无法完全避免) | 程序逻辑错误(开发者应通过编码避免) |
| 处理策略 | 必须显式处理,以应对可预见的失败。 | 应通过代码审查和防御性编程来根除,而非捕获。 |
| 典型示例 | IOException,SQLException | NullPointerException,ArrayIndexOutOfBoundsException |
注意
重载和重写关于异常的不同处理
重写时抛出的异常必须小于等于父类异常
重载则无关
自定义异常
- 编码时可以自定义异常,需继承自Exception。
- 如果继承的是运行时异常,使用时无需额外处理。
- 如果继承的是检查异常,使用时需要try-catch捕获或者throws向上抛。
异常处理机制
try-catch-finally:异常处理的基础结构
基本结构与执行流程
- try 块:包裹可能抛出异常的代码。 catch 块:捕获并处理特定类型的异常。一个 try 块后可以跟多个 catch 块。
finally 块:无论是否发生异常,也无论 try 或 catch 中是否有 return 语句,finally
块中的代码几乎总会执行。它常用于资源清理,如关闭连接、释放锁等。
注意点
- 慎用 finally 中的 return
- 在 finally 块中使用 return 语句会覆盖 try 或 catch 块中的返回值,可能导致异常信息丢失或返回错误的结果,应极力避免
try-with-resources:自动资源管理
try-with-resources 是 JDK7 引入的语法,只要实现了 AutoCloseable 接口的资源(流、连接、锁等),都可以在 try 后声明,执行完毕会自动关闭,不用手动写 finally,代码更简洁、避免漏关资源
语法与工作原理
资源在 try 关键字后的括号内声明和初始化。当 try 块执行完毕(无论是正常结束还是因异常退出),JVM会自动按照声明的逆序调用资源的 close() 方法。
// 语法示例try(FileInputStreamfis=newFileInputStream("test.txt");BufferedReaderbr=newBufferedReader(newInputStreamReader(fis))){// 使用资源Stringline=br.readLine();}catch(IOExceptione){// 处理异常}// 在这里,br 和 fis 会被自动关闭,无需 finally 块关键点
- 资源声明在 try(…) 内部,JVM 自动调用 close()
- 关闭顺序与声明顺序相反
- 支持同时声明多个资源,用分号分隔
- 所有InputStream/OutputStream、Connection、Statement、RandomAccessFile 等都已实现AutoCloseable
自定义异常
自定义异常的核心目的是让异常携带业务语义。
核心要素
一个优秀的自定义异常类通常包含以下要素:
- 继承体系:
- 业务异常:通常继承 RuntimeException(非检查型),避免在方法签名上堆砌 throws,保持代码整洁。
- 强制处理异常:继承 Exception(检查型),适用于调用方必须处理的场景(如参数校验失败)。
- 错误码:用于前端或调用方快速识别错误类型,而不必依赖易变的错误消息文本。
- 上下文信息:如 userId, orderId 等,帮助定位具体是哪条数据出了问题