什么时候适合抛出异常?

When is it suitable to throw an Exception?

我最近看到一些代码,其中作者在 returns int:

的方法中为几乎每个构造函数抛出异常并为下面的代码抛出运行时异常
if(condition){
  return 1;
}
if(condition){
  return 2;
}
if(condition){
  return 3;
}
throw new RuntimeException("Unreachable code");
// method ends here

我个人不会在那里抛出异常,因为我会使用 if 和 else if 语句来构造它,在这种特殊情况下,你的代码根本就错了,因为它无论如何都不满足其中一个条件.

有很多地方你可以抛出运行时异常,如果你的代码正常工作,这些异常永远不会发生,有时看起来作者不相信代码可以工作,在这种情况下上面的代码块。此外,如果每个构造函数未正确初始化,它都可以抛出异常,但您也可以构造它以使对象为 null - 例如,您可以随后在 main 中检查它。

基本上,我要问的是什么时候值得抛出异常?

例外的要点是传达例外情况。

从这个意义上说:如果在您的示例中所有条件都是 false 绝对出乎意料,并且也没有有效的 return 值来表明情况下,然后抛出 RuntimeException 是在这里做的合理的事情;但我可能会将消息更改为:

throw new RuntimeException("All conditions failed: " + some data)

如前所述:这是关于沟通;在这种情况下,调试问题的人。因此,在此处包含了解为什么所有这些检查都得到结果所需的信息可能会有所帮助 false

重点是:该方法有合同;该合同应包括此类细节。意思是:如果那个方法是public,你可能应该添加一个@throws RuntimeException 并有一个清晰的描述。

在这种情况下使用 RuntimeException 也是一种有效的做法;正如您所做的那样, 想在各处使用已检查的异常来污染您的方法签名。

编辑:当然,平衡 是必需的。示例:我的 类 通常看起来像:

public class Whatever {
  private final Foo theFoo;

  public Whatever(Foo theFoo) {
   Objects.requireNonNull(theFoo, "theFoo must not be null");
   this.theFoo = theFoo;

因此,我的构造函数可能会抛出一个 NPE;是的。但是:只有那里。我所有的方法都可以依赖于所有字段都被初始化为非空的事实;并且它们是最终的,所以它们将永远是非空的。

意思是:人要保持理性; "develop" 感觉:哪些问题是例外但可能发生的;哪些是不可能的,以至于您不会到处污染您的代码来检查它们。

终于;只是为了说明这一点 - 添加例外只是等式的 一个 部分。当有东西抛出时,您需要抓住一些东西!因此,正如所说:平衡出现了。无论你在代码中做什么,都必须 "add value" 。如果您的代码没有实现明确定义的目的,那么很有可能:您不需要它!

GhostCat 基本上涵盖了我们应该何时以及为何应该使用异常的所有需要​​说明的内容。更进一步,最好的办法是权衡包含异常的成本效益。在这种情况下,成本指的是性能以及应用程序的客户端友好性下降,而收益是应用程序的流畅 运行 以及用户友好性。在我看来,首先应该区分应用程序错误和系统错误。然后将这些错误分为编译时和 运行 时(注意,编译时错误通常不需要异常处理,而是调试并找出需要使用调试工具处理的问题)例如 C++ 的断言)。即使包含异常处理程序的细节取决于特定应用程序的上下文,但通常可以假设以下原则作为起点:

1-识别代码的关键热点崩溃点;

2- 区分系统错误和应用程序错误;

3-识别运行时间和编译时错误;

4- 使用断言或预处理器指令等调试工具处理编译时错误。此外,包括异常处理程序或跟踪或调试以处理 运行 时间错误 4-权衡运行次处理异常的后果;

5- 然后提供一个可测试的框架,通常可以在单元测试期间处理,以确定需要包含或不包含异常的地方。

6- 最后,考虑您认为决定性的因素以及需要包含异常处理程序来处理它们的因素,决定您需要在何处为生产代码包含异常处理程序。

7- 终于……你需要有一个防崩溃异常处理程序,它应该在应用程序崩溃的不太可能的情况下被触发,并包括回退安全来处理状态,使应用程序非常用户友好。