来自 Effective Java (Joshua Bloch)
- 仅对异常情况使用 Exceptions(切勿用于普通控制流)
- 对可恢复条件使用检查异常,对编程错误使用运行时异常。
- 避免不必要地使用检查异常
避免检查异常。
http://www.mindview.net/Etc/Discussions/CheckedExceptions
http://www.ibm.com/developerworks/java/library/j-jtp05254/index.html
- 已检查的异常通常被许多人认为是一个有缺陷的功能。这不是一个坏主意,但人们并不真正了解如何使用它们。
- Java 框架,如 Spring、Hibernate……它们大多都抛出未经检查的异常。
- C# 没有故意实现检查异常。斯卡拉也没有。
- 不是因为不检查就抓不到。
- 不是不勾选就不能翻译(换行)
- 这不是因为它未经检查就不是合同的一部分。实际上,您可以声明该方法以引发未经检查的异常。
- 检查异常增加了客户端和库之间的耦合
要理解的一件非常重要的事情是任何一段代码都可能产生异常。
并不是因为一个方法声明抛出一个 IOException,它就不会抛出任何其他异常。它可以抛出任何其他运行时异常(通用或自定义)。对于已检查的异常,开发人员倾向于相反的想法,认为捕获 IOException 将处理所有异常情况,但事实并非如此!
仅编译时功能
当您忘记捕获或重新抛出已检查的异常时,只有编译器会告诉您。在运行时,没有区别。
这意味着通过使用类型擦除技巧,您可以抛出一个检查异常,甚至不需要它成为方法契约的一部分。
您可以在此处找到此技巧的示例,称为 SneakyTrow:
https ://stackoverflow.com/a/4890489/82609
Lombok 还提供了一个 @SneakyThrow 注释来放置方法,这样您就不需要在方法签名中声明已检查的异常。
仅当您的类客户端可能从异常中恢复时才使用已检查异常。
这是太阳的建议。
基本上,连接到数据库的尝试将引发检查异常,并且重试策略代码将在连接尝试时捕获这些检查异常。当超过重试次数时,重试策略会抛出未经检查的异常,这意味着它不是可恢复的异常,因为恢复策略已经被尝试过。顺便说一下,您可以使用 Spring RetryTemplate 。
避免异常代码
异常类型应该足以用于流控制决策。解析异常或流控只会产生无用的代码。添加更多异常类型,就像您有异常代码一样。
快速失败
让所有不可恢复的异常都被抛出到 IHM 层。如果您使用声明检查异常的框架并且您没有针对它们的恢复策略,请不要犹豫将它们包装到未经检查的异常中。
如果你不能恢复,那么你不应该做“catch and log”。或者更糟糕的是,您不应该执行“捕获并返回 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
或者,您可以使用 Java 原生断言或一些自定义代码。这有助于快速失败。