API中规范处理各类异常的方法?自定义异常能否处理RuntimeException?
一、API中处理各类异常的正确方式
SonarLint提示不能抛出泛化的Exception,核心原因是它过于宽泛,调用者无法明确知晓具体可能遇到的异常类型,不利于异常的针对性处理。针对你的API(项目A)和实现(项目B)场景,正确的处理方式如下:
定义特定的自定义受检异常
针对API的业务场景(比如Builder创建操作),定义专属的受检异常,替代顶层的Exception。这样API的抛出列表语义清晰,调用者能直观了解操作失败的可能原因。示例修改后的API接口:
public interface IBuilder { void create() throws BuilderCreationException; }对应的自定义受检异常(遵循Java命名规范,首字母大写):
public class BuilderCreationException extends Exception { // 提供多参构造方法,支持携带错误消息和底层异常原因 public BuilderCreationException(String message) { super(message); } public BuilderCreationException(String message, Throwable cause) { super(message, cause); } }实现类中统一包装异常
在项目B的实现类里,不管是遇到受检异常还是运行时异常,都可以将其包装为API定义的自定义异常抛出:- 对于受检异常:必须捕获后包装,或者直接抛出(需符合API的throws声明)
- 对于运行时异常:可以选择直接让其传播(无需在throws声明),或者捕获后包装为自定义异常,统一对外暴露的异常类型
示例实现类代码:
public abstract class ABuilder implements IBuilder { public void create() throws BuilderCreationException { try { // 原实现逻辑,可能抛出各类异常 throw new SomeImplSpecificException(); } catch (Exception e) { // 将底层异常包装为API约定的异常,保留异常链便于排查 throw new BuilderCreationException("构建操作失败", e); } } } public class ARealBuilder extends ABuilder { public void create() throws BuilderCreationException { try { // 可能触发受检异常的逻辑 if (fileNotFound()) { throw new IOException("依赖文件不存在"); } // 可能触发运行时异常的逻辑 if (invalidParam()) { throw new IllegalArgumentException("参数不符合要求"); } } catch (IOException e) { throw new BuilderCreationException("构建时IO错误", e); } // 运行时异常若不捕获,会自动向上传播,无需在方法throws中声明 } }
二、自定义myException能否处理RuntimeException?
你定义的myException(继承Exception)属于受检异常,它不能直接“处理”RuntimeException,但可以通过包装的方式将RuntimeException转换为受检异常对外抛出:
如果实现类中抛出RuntimeException且不捕获,该异常会直接向上传播,不受
myException声明的限制(因为RuntimeException是未受检异常,不需要方法在throws中声明)。如果需要将RuntimeException统一为自定义异常对外暴露,需要手动捕获RuntimeException,然后包装成
myException抛出:public void create() throws myException { try { // 触发运行时异常的逻辑 throw new NullPointerException("核心对象为空"); } catch (RuntimeException e) { // 将运行时异常包装为自定义受检异常 throw new myException("构建过程中出现运行时错误", e); } }
需要注意:通常不建议强行将RuntimeException包装为受检异常,因为运行时异常一般代表程序逻辑错误(比如空指针、参数非法),这类错误更适合让调用者自行处理或终止程序,而非强制要求捕获。
内容的提问来源于stack exchange,提问作者bobier2

