根本区别在于是否该由程序员捕获处理:Error是JVM级不可恢复故障,不应捕获;Exception中checked异常必须try-catch或throws,unchecked异常(RuntimeException)可不处理但需修复。

Java里Error和Exception的根本区别在哪
根本区别不在“谁更严重”,而在于「是否该由程序员捕获并处理」。JVM设计上把 Error 定义为「程序本不该尝试恢复的系统级故障」,比如 OutOfMemoryError 或 NoClassDefFoundError;而 Exception(尤其是 RuntimeException 以外的)代表「预期中可能出现、且业务逻辑有能力响应的异常情况」,比如 IOException 或 SQLException。
哪些Exception必须try-catch,哪些可以不写
Java用「检查型异常(checked exception)」强制你面对潜在失败。所有继承自 Exception 但**不继承自 RuntimeException** 的类都属于这一类——编译器会报错:「unreported exception XXX; must be caught or declared to be thrown」。
常见 checked exception:IOException、SQLException、ClassNotFoundException
常见 unchecked exception(即 RuntimeException 及其子类):NullPointerException、ArrayIndexOutOfBoundsException、IllegalArgumentException
立即学习“Java免费学习笔记(深入)”;
- 必须 try-catch 或在方法签名加
throws:对FileInputStream构造时抛出的FileNotFoundException - 可以不写 try-catch:调用
list.get(100)抛出的IndexOutOfBoundsException,编译器不管 - 但注意:
RuntimeException不等于“可以忽略”——它往往暴露的是代码缺陷,比如空指针,应该修复而非吞掉
为什么不要catch Error,哪怕用了try-catch也大概率无效
catch Error 在语法上是允许的,但几乎总是错误的设计。因为 Error 表示 JVM 自身已处于不稳定状态,比如:
-
StackOverflowError:当前线程栈已爆,连 catch 块里的代码都可能无法安全执行 -
OutOfMemoryError:堆或元空间耗尽,new 一个String都可能失败 -
LinkageError子类(如NoClassDefFoundError):类加载链已损坏,后续行为不可预测
典型反例:
try {
someUnstableNativeCall();
} catch (Error e) {
// ❌ 错误:e.printStackTrace() 可能因内存不足而失败,日志都写不出
log.error("Caught Error", e);
System.exit(1); // 更糟:粗暴退出,跳过正常关闭流程
}正确做法是让 JVM crash 并生成 heap dump 或 hs_err_pid.log,然后靠监控告警+日志分析定位根因。
自定义异常该继承Exception还是RuntimeException
取决于「这个异常是否属于业务流程中可预期、可恢复的分支」。
- 如果调用方**必须感知并决策**(例如支付失败需提示用户重试或换卡),就继承
Exception,强制调用方处理 - 如果本质是参数校验失败、状态非法等「本不该发生,发生了说明调用方有 bug」,就继承
RuntimeException,避免污染 API 签名
示例:
public class InsufficientBalanceException extends Exception { ... }
// 调用转账方法时必须处理余额不足——这是业务核心路径的一部分
public class InvalidOrderStatusException extends RuntimeException { ... }
// 订单从"已取消"状态调用发货接口?这属于非法调用,应快速 fail-fast
别为了省事全用 RuntimeException;也别为了“看起来严谨”把所有异常都设为 checked——过度检查会让调用方大量写空 catch 或 throw new RuntimeException(e),反而掩盖问题。










