JAVA SE 基础语法 —— K / 认识异常
一、异常的概念与体系结构
(一)异常的概念
- 定义:程序执行过程中发生的不正常行为(如算术错误、数组越界、空指针等),Java 中每种异常均对应专属类描述
- 常见异常示例:
- 算术异常(
ArithmeticException
):如10 / 0
- 数组越界异常(
ArrayIndexOutOfBoundsException
):如访问数组不存在的下标 - 空指针异常(
NullPointerException
):如调用null
对象的方法 / 属性
- 算术异常(
(二)异常的体系结构
- 顶层类:
Throwable
,派生出两大核心子类:- Error:JVM 无法解决的严重问题(如
StackOverflowError
栈溢出、OutOfMemoryError
内存溢出),程序无法恢复,直接终止 - Exception:程序员可通过代码处理的异常,是日常开发中关注的核心,处理后程序可继续执行
- Error:JVM 无法解决的严重问题(如
(三)异常的分类
分类 | 发生时机 | 特点 | 典型示例 |
---|---|---|---|
编译时异常 | 程序编译期间 | 又称 “受检查异常”,必须显式处理(捕获或声明抛出),否则无法通过编译 | CloneNotSupportedException |
运行时异常 | 程序执行期间 | 又称 “非受检查异常”,继承自RuntimeException ,无需显式处理,默认交给 JVM | NullPointerException 、ArithmeticException |
- 注意:编译期语法错误(如拼写错误)不属于异常,仅编译通过后 JVM 执行时的错误才是异常
二、异常的处理
(一)防御式编程思想
- LBYL(事前防御型):操作前充分检查(如判断登录、匹配等步骤是否成功),正常流程与错误处理代码混合,可读性差
- EAFP(事后认错型):先执行操作,遇到异常再处理,正常流程与错误流程分离,代码更清晰,是异常处理的核心思想
(二)异常的核心关键字
包括throw
(抛出异常)、try
(包裹可能异常的代码)、catch
(捕获异常)、finally
(必执行的收尾代码)、throws
(声明异常)
(三)异常的抛出(throw)
- 语法:
throw new XXXException("异常原因");
,需写在方法体内部 - 规则:
- 抛出对象必须是
Exception
或其子类 - 抛出运行时异常(
RuntimeException
子类):无需显式处理,交给 JVM - 抛出编译时异常:必须显式处理(捕获或声明抛出),否则编译报错
- 异常抛出后,后续代码不再执行
- 抛出对象必须是
(四)异常的捕获
1. 异常声明(throws)
- 语法:
修饰符 返回值类型 方法名(参数列表) throws 异常类型1, 异常类型2...{ }
,写在方法参数列表后 - 作用:当前方法不处理异常,将异常抛给调用者处理(仅声明,未真正处理)
- 规则:
- 声明的异常需是
Exception
或其子类 - 方法内部抛出多个异常时,
throws
后需列出所有异常;若异常有父子关系,仅声明父类即可 - 调用声明异常的方法时,调用者必须处理异常(继续
throws
或try-catch
)
- 声明的异常需是
2. try-catch 捕获处理
- 语法:
plaintext
try{// 可能异常的代码 }catch(异常类型1 e){// 处理异常1 }catch(异常类型2 e){// 处理异常2 }finally{// 必执行的收尾代码 }
- 核心逻辑:
try
:包裹可能抛出异常的代码,异常抛出后后续代码不执行catch
:按类型匹配异常,匹配成功则处理;多个catch
需子类异常在前、父类异常在后,避免语法错误finally
:无论是否异常,均会执行,常用于资源回收(如关闭 IO 流、数据库连接)
- 异常处理方式:
- 打印异常信息:
e.getMessage()
(仅异常原因)、e.toString()
(异常类型 + 原因)、e.printStackTrace()
(完整调用栈,推荐) - 业务处理:严重异常可终止程序,轻微异常可记录日志,网络相关异常可重试
- 打印异常信息:
(五)异常的处理流程
- 执行
try
中的代码,若出现异常,终止try
并匹配catch
中的异常类型 - 匹配成功则执行对应
catch
的处理代码;未匹配则将异常向上传递给上层调用者 - 无论是否匹配,均执行
finally
中的代码(方法结束前执行) - 若上层调用者仍未处理,继续向上传递,直至
main
方法;main
方法未处理则交给 JVM,程序异常终止
三、自定义异常类
(一)自定义原因
Java 内置异常无法覆盖所有业务场景(如用户名错误、密码错误),需创建符合业务的异常类
(二)实现步骤
- 继承
Exception
(编译时异常,需显式处理)或RuntimeException
(运行时异常,无需显式处理) - 实现带
String
参数的构造方法,参数为异常原因(调用父类构造方法super(message)
)
(三)使用场景
如登录功能中,用户名错误抛出UserNameException
,密码错误抛出PasswordException
,明确区分业务异常类型,便于精准处理