该用throw时是当前状态无法合法执行须调用方立即决策,如非空id传null、库存为0下单;不该用时是替代正常返回或循环中逐个抛异常。

throw 什么时候该用,什么时候不该用
主动抛出异常不是为了“显得代码有错误处理”,而是当函数/方法发现当前状态无法继续合法执行时,必须让调用方立刻感知并决策。比如用户传了 null 但业务逻辑明确要求非空 ID,或库存为 0 却收到下单请求——这类场景下不抛错,后续流程大概率会出更隐蔽的 bug(比如空指针、负库存、数据不一致)。
反例:用 throw 替代正常返回值(如用 throw new RuntimeException("success") 表示成功),或者在循环里对每个失败项都 throw(应收集错误后统一返回)。
Java 中 throw 自定义异常的最小可行写法
别一上来就写一堆注解和构造器。先确保能跑通、能被捕获、能带关键信息:
- 定义异常类继承
RuntimeException(非检查异常,调用方不用强制 try-catch,适合业务校验) - 至少提供一个带
String message的构造器 - 抛出时传入具体上下文,比如订单号、用户 ID、字段名
public class InsufficientStockException extends RuntimeException {
public InsufficientStockException(String orderId, int requested, int available) {
super(String.format("Order %s: requested %d, but only %d in stock", orderId, requested, available));
}
}
使用:if (stock
Node.js 里 throw Error 和 Promise.reject 的区别
同步流程中直接 throw new Error("xxx") 没问题;但异步链里乱 throw 会导致未捕获异常(Uncaught Exception),尤其在 Promise 或 async/await 中:
-
throw在async函数里等价于return Promise.reject(...),会被catch捕获 - 但在
.then()回调里throw,必须配对.catch(),否则静默失败 - 千万别在
setTimeout或事件回调里 throw —— 它脱离 Promise 链,只能靠全局process.on('uncaughtException')拦截,极难调试
推荐写法:if (!user) throw new Error(`User not found: ${id}`);(在 async 函数内),比手动 Promise.reject 更直观且不易漏 catch。
Python raise 的常见陷阱
Python 的 raise 看似简单,但两个细节容易导致异常信息丢失或难以定位:
- 用
raise ValueError("msg")没问题;但若想包装底层异常(比如数据库异常),别写raise ValueError("DB failed")—— 这会丢掉原始 traceback。应该用raise ValueError("DB failed") from exc - 自定义异常类不要只继承
Exception,优先考虑语义更明确的基类,比如校验失败用ValueError,权限问题用PermissionError,方便上层用不同 except 分支处理 - 避免在
except块末尾裸写raise(无参数),它虽能重抛,但一旦中间有其他异常干扰(比如日志写入失败),原始异常可能被覆盖
真正需要中断非法流程时,异常类型要足够具体,消息里要包含可操作线索(比如 “字段 email 格式错误:‘abc’ 不符合 RFC 5322”),而不是 “参数错误”。










