来自《Effective Java》(Joshua Bloch)
- 仅在异常情况下使用 Exceptions(切勿用于普通控制流)
- 对可恢复条件使用检查异常,对编程错误使用运行时异常。
- 避免不必要地使用已检查异常
避免检查异常。
http://www.mindview.net/Etc/Discussions/CheckedExceptions http://www.mindview.net/Etc/Discussions/CheckedExceptions
http://www.ibm.com/developerworks/java/library/j-jtp05254/index.html http://www.ibm.com/developerworks/java/library/j-jtp05254/index.html
- 检查异常通常被许多人认为是一个有缺陷的功能。这不是一个坏主意,但人们并不真正了解如何使用它们。
- 像 Spring、Hibernate 这样的 Java 框架......它们大多都会抛出未经检查的异常。
- C# 没有故意实现检查异常。斯卡拉也没有。
- 并不是因为它不受控制,所以你无法抓住它。
- 并不是因为没有勾选所以不能翻译(换行)
- 并不是因为它未经检查,所以它不是合同的一部分。事实上,您可以声明抛出未经检查的异常的方法。
- 检查异常增加了客户端和库之间的耦合
需要理解的一件非常重要的事情是任何一段代码都可能产生异常。并不是因为一个方法声明抛出 IOException,它就不能抛出任何其他异常。它可以抛出任何其他运行时异常(通用或自定义)。对于受检查的异常,开发人员倾向于相反的想法,并认为捕获 IOException 将处理所有异常情况,但事实并非如此!
仅编译时功能
当您忘记捕获或重新抛出已检查的异常时,只有编译器会告诉您。在运行时,没有区别。
这意味着通过使用类型擦除技巧,您可以抛出已检查的异常,甚至不需要它成为方法契约的一部分。
您可以在此处找到此技巧的示例(称为 SneakyTrow):https://stackoverflow.com/a/4890489/82609 https://stackoverflow.com/a/4890489/82609
Lombok 还提供了一个 @SneakyThrow 注释来放置方法,这样您就不需要在方法签名中声明检查的异常。
仅当类客户端可能从异常中恢复时才使用已检查异常。
这是太阳的推荐。
基本上,尝试连接到数据库将引发检查异常,并且重试策略代码将在连接尝试时捕获这些检查异常。当超过重试次数时,重试策略将抛出未经检查的异常,这意味着它不是可恢复的异常,因为恢复策略已经被尝试过。
顺便说一下,您可以使用 Spring RetryTemplate 来实现这一点。
避免异常代码
异常类型应该足以用于流量控制决策。解析异常或流程控制只会创建无用的代码。添加更多异常类型,只要有异常代码即可。
快速失败
让所有不可恢复的异常被抛出到 IHM 层。
如果您使用声明检查异常的框架,并且没有针对它们的恢复策略,请毫不犹豫地将它们包装到未检查异常中。
如果您无法恢复,那么您不应该执行“捕获并记录”。或者更糟糕的是,您不应该执行“catch and return null”。这将产生不一致的软件,并且稍后您的程序中可能会出现另一个异常,但您将无法理解原因。返回 null 只会在稍后创建 NullPointerException。
IHM层技术可以具有异常处理程序/映射器。
Web IHM 层具有异常映射器,因此您可以说“此异常产生 404 错误”。
功能性方法
仅供参考:在函数式语言中,使用异常进行流量控制通常被认为是一种不好的做法。
我们通常不抛出异常,而是返回“增强类型”,例如 Either[Error,MyResultType]。
返回的实例要么是错误,要么是成功,成功是返回的 MyResultType 实例。
异常对于流量控制不具有性能
创建异常是有成本的(创建堆栈跟踪)。它的成本比使用 if, else 的正常流程要高得多...
如果可以避免,请勿将它们用于流量控制。
基本上,您基本上总是可以避免它们,但在 Java 中,在某些情况下使用它们进行流量控制有时可能更方便。在函数式语言中,Either monad 再次发挥作用。
使用断言
如果开发人员认为程序中的某些内容是正确的,请使用断言,以便保证您的断言是正确的。
看看番石榴先决条件:https://code.google.com/p/guava-libraries/wiki/PreconditionsExplained https://code.google.com/p/guava-libraries/wiki/PreconditionsExplained
或者您可以使用 Java 本机断言或一些自定义代码。
这有助于快速失败。