尝试捕获会降低效率吗?

时间:2018-04-16 05:11:00

标签: java performance try-catch

之间存在效率差异: -

public boolean canDivisionBeDone(int iA, int iB){

  try{
      float a = iA/iB;
    }catch(Exception e){
    return false;
 }

return true;
}

public boolean canDivisionBeDone(int iA, int iB){

 if(iB == 0){
     return false;
 }else{
         float a = iA/iB;
 }

return true;
}

如果是,为什么?

3 个答案:

答案 0 :(得分:1)

使用try本身没有任何费用,但如果使用块创建了太多异常,则应尝试检查您的代码。

  

在Java中创建异常是一个非常慢的操作。期望抛出异常会花费你大约1-5微秒。几乎所有这些时间都花在填充异常线程堆栈上。堆栈跟踪越深,填充它的时间就越长。

有关详细信息,请参阅here

答案 1 :(得分:1)

从编码的角度来看,我肯定更喜欢条件(a == 0 ? 0 : (a/b)),而不是异常处理。这实际上不是特殊情况,因此此处不应将异常用于控制流程。

关于效率,我写了一个微基准来测试这个:

@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MyBenchmark {

    private int a = 10;
    private int b = (int) Math.floor(Math.random());

    @Benchmark
    public float conditional() {
        if (b == 0) {
            return 0;
        } else {
            return a / b;
        }
    }

    @Benchmark
    public float exceptional() {
        try {
            return a / b;
        } catch (ArithmeticException aex) {
            return 0;
        }
    }
}

结果:

Benchmark                Mode  Cnt  Score   Error  Units
MyBenchmark.conditional  avgt  200  7.346 ± 0.326  ns/op
MyBenchmark.exceptional  avgt  200  8.166 ± 0.448  ns/op

因为我对JMH很新,I am not sure my benchmark is correct。但是从表面上看结果,“特殊”方法有点(~10%)慢。说实话,我期待更大的差异。

答案 2 :(得分:0)

您想要传播回调用方的异常情况的例外情况。在正常操作期间不要依赖例外。

我只想把你的代码写成:

public boolean canDivisionBeDone(int iA, int iB) {
    return iB != 0;
}

但回答你的问题:try-catch-finally是使用离线异常表在Java中实现的,因此,当没有异常被抛出时,是zero-overhead

以下是两个函数的字节码的样子:

  public boolean canDivisionBeDoneTryCatch(int, int);
    Code:
       0: iload_1
       1: iload_2
       2: idiv
       3: i2f
       4: fstore_3
       5: goto          11
       8: astore_3
       9: iconst_0
      10: ireturn
      11: iconst_1
      12: ireturn
    Exception table:
       from    to  target type
           0     5     8   Class java/lang/Exception

  public boolean canDivisionBeDoneIf(int, int);
    Code:
       0: iload_2
       1: ifne          6
       4: iconst_0
       5: ireturn
       6: iload_1
       7: iload_2
       8: idiv
       9: i2f
      10: fstore_3
      11: iconst_1
      12: ireturn

正如你所看到的那样,快乐的道路几乎完全相同。

但是,抛出异常是很昂贵的。

所以是的,我希望异常版本会稍慢,具体取决于iB == 0情况的比例。

如有疑问,请以此为基准。