Java中的异常类型与异常分类

Error是JVM无法恢复的严重问题(如OutOfMemoryError),不强制处理;Exception分Checked(编译器强制处理,如IOException)和Unchecked(RuntimeException子类,如NullPointerException),需依上下文决定捕获、记录或抛出。

Java中ExceptionError的根本区别

不是所有“异常”都该被catch——Error代表JVM无法恢复的严重问题,比如OutOfMemoryErrorStackOverflowError;而Exception是程序本可预期、可干预的异常情况。JVM不强制处理Error,但编译器会强制你处理Checked Exception(如IOException),除非你声明抛出或捕获它。

常见误操作:把catch (Exception e)写成万能兜底,结果连NoClassDefFoundError这类Error也试图捕获,既无意义又掩盖真实故障点。

Checked Exception必须显式处理的三个原因

Java设计上要求你直面I/O、网络、类加载等外部不确定性。不处理FileNo

tFoundExceptionSQLException,代码直接编译失败。

  • 不写try-catch?必须在方法签名加throws声明,把责任明确向上移交
  • 子类重写父类方法时,不能抛出比父类更宽泛的Checked Exception(比如父类声明throws IOException,子类不能改写为throws Exception
  • 使用Lambda或函数式接口时,若内部调用含Checked Exception的方法(如Files.readAllLines()),需自行包装为RuntimeException,否则编译不过

Unchecked ExceptionRuntimeException及其子类)的典型陷阱

它们不强制捕获,但不代表可以忽略。多数源于编程逻辑错误,比如NullPointerExceptionArrayIndexOutOfBoundsExceptionIllegalArgumentException

容易踩的坑:

  • finally块里执行可能抛出RuntimeException的操作(如关闭已为null的资源),导致掩盖原始异常
  • 自定义业务异常继承RuntimeException却不带语义化构造函数,导致日志里只看到MyBizException,没有关键上下文
  • Optional.get()代替判空,结果触发NoSuchElementException——这属于典型的可预防Unchecked Exception

如何判断一个异常该捕获、该记录、还是该抛出

关键看「当前代码是否拥有足够上下文做决策」:

  • 读配置文件失败?IOException应捕获并转为IllegalStateException(带配置路径信息),因为调用方不关心IO细节,只关心“启动失败”
  • 数据库查询返回空结果?这不是异常,是正常业务分支,不该抛RuntimeException,应返回Optional.empty()null
  • 调用第三方HTTP API超时?若重试逻辑在上层统一处理,当前层就该原样抛出SocketTimeoutException,而不是catch后吞掉或打印日志了事

最常被忽略的一点:同一个异常在不同层级语义不同。比如NumberFormatException在参数解析层是输入错误,该返回400;但在内部计算层出现,大概率是上游数据污染,该报警而非静默容错。