我最近看到一些代码,其中作者几乎为每个构造函数抛出了异常,并在返回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中检查它。
我基本上要问的是什么时候值得抛出异常?
答案 0 :(得分:4)
例外点是沟通例外情况。
从这个意义上讲:如果您的示例中的所有条件都是 false 是绝对意外的,并且没有有效的返回值来指示该情况,那么抛出该RuntimeException是合理的要做的事情;但我可能会将消息更改为:
throw new RuntimeException("All conditions failed: " + some data)
如上所述:它是关于沟通;在这种情况下,调试问题的人。因此,在此处包含所需信息可能会有所帮助,以便了解所有这些检查结果的原因false
。
重点是:该方法有合同;该合同应包括此类细节。含义:如果该方法是公共的,您应该添加一个带有清晰描述的@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;是。但是:只有那里。我的所有方法都可以依赖于所有字段都被初始化为非null的事实;它们是最终的,所以它们永远都是非空的。
含义:必须保持合理;并“发展”一种感觉:哪些问题是特殊但可能的;哪些是不可能的,你不会污染你的代码到处检查它们。
最后;只是为了明确这一点 - 添加例外只是等式中的一个部分。什么东西抛出,那么你需要抓住一些东西!因此,如上所述:平衡进来。无论你在代码中做什么都必须“增加价值”。如果您的代码没有达到明确的目的,那么很可能是:您不需要它!
答案 1 :(得分:-1)
GhostCat基本上涵盖了我们应该何时以及为什么要使用异常时需要说明的内容。为了更进一步,最好的办法是权衡包含例外的成本效益。此上下文中的成本是指应用程序的性能以及降低的客户端友好性,而好处是应用程序的平稳运行以及用户友好性。在我看来,第一个应该区分应用程序和系统错误。然后,在将它们分解为编译和运行时之后,还需要仔细检查这些错误(请注意,编译时错误通常不需要处理异常,而是调试并找出使用调试工具(如断言C ++)处理它们所需的问题)。即使包含异常处理程序的细节依赖于特定应用程序的上下文,通常也可以假设以下原则作为起点:
1-识别代码的关键热点崩溃点;
2-区分系统和应用程序错误;
3 - 识别运行时和编译时错误;
4-使用assert或preprocessor指令等调试工具处理编译时错误。此外,还包括异常处理程序或跟踪或调试以处理运行时错误 4 - 权衡在运行时处理异常的后果;
5-然后提供一个可测试的框架,通常可以在单元测试期间处理,以确定需要包含异常的位置。
6-最后,确定您需要在生产代码中包含异常处理程序的位置,同时考虑您认为具有决定性的因素,并且需要包含处理它们的异常处理程序。
7-最后终于....你需要有一个崩溃证明异常处理程序,应该在应用程序崩溃的不太可能的场景中触发,并包括回退安全性来处理状态以使应用程序非常用户友好。