哪个更好/更有效:检查错误值或捕获Java中的异常

在Java中哪个更有效:检查错误值以防止异常发生或让异常发生并捕获它们?

下面是两个示例代码块来说明这种差异:

void doSomething(type value1) {
    ResultType result = genericError;

     if (value1 == badvalue || value1 == badvalue2 || ...) {
          result = specificError;
     } else {
          DoSomeActionThatFailsIfValue1IsBad(value1);
          // ...
          result = success;
     }
     callback(result);
}

void doSomething(type value1) {
     ResultType result = genericError;
     try {
          DoSomeActionThatFailsIfValue1IsBad(value1);
          // ...
          result = success;
     } catch (ExceptionType e) {
          result = specificError;
     } finally {
          callback(result);
     }
}

一方面,你总是在做比较。另一方面,老实说,我不知道系统的内部做了什么来生成异常,抛出它,然后触发catch子句。它有效率较低的声音,但如果在非错误情况下它不会增加开销,那么平均而言,它的效率会更高。这是什么?它是否添加了类似的检查?在为异常处理添加的隐式代码中是否进行了检查,即使使用额外的显式检查层也是如此?也许这总是取决于异常的类型?我没有考虑什么?

让我们也假设所有“坏值”都是已知的 - 这是一个明显的问题。如果您不知道所有坏值 - 或者列表太长且不规则 - 那么异常处理可能是唯一的方法。

那么,每种方法的优缺点是什么,为什么?

需要考虑的附带问题:

  • 如果值在大多数时候是“坏的”(会引发异常),你的答案会如何变化?
  • 这在多大程度上取决于正在使用的 VM 的具体情况?
  • 如果对语言X提出同样的问题,答案会有所不同吗?(更一般地说,这是在询问是否可以假设检查值总是比依赖异常处理更有效,因为它增加了当前编译器/解释器的更多开销。
  • (新)引发异常的操作很慢。即使没有引发异常,进入 try 块是否有开销?

与SO的相似之处:

  • 这与此答案中的代码示例类似,但指出它们仅在概念上相似,而不是编译的现实。
  • 前提类似于这个问题,但在我的情况下,任务的请求者(例如“Something”)不是方法的调用者(例如“doSomething”)(因此没有返回)。
  • 这个非常相似,但我没有找到我问题的答案。

  • 与太多其他问题类似,除了:

    我不是在问理论上的最佳实践。我问更多关于运行时性能和效率的问题(这应该意味着,对于特定情况,有非意见答案),特别是在资源有限的平台上。例如,如果唯一的坏值只是一个空对象,那么检查它还是只是尝试使用它并捕获异常会更好/更有效?


答案 1

"如果值在大多数时候是“坏的”(会引发异常),你的答案会如何变化?我认为这是关键所在。与比较相比,异常的开销很大,因此您确实希望对异常情况使用异常。

同样,您关于此答案如何根据语言/环境而变化的问题与此相关:异常的费用在不同的环境中是不同的。例如,.Net 1.1 和 2.0 在第一次引发异常时非常慢。


答案 2

纯粹从效率的角度来看,并给出您的代码示例,我认为这取决于您期望看到不良值的频率。如果坏值不是太少见,则进行比较会更快,因为异常成本很高。但是,如果坏值非常罕见,则使用异常可能会更快。

不过,最重要的是,如果你正在寻找性能,请分析你的代码。这个代码块甚至可能不是一个问题。如果是,则尝试两种方式,看看哪个更快。同样,这取决于您期望看到不良值的频率。


推荐