Пытается ли улов снизить эффективность?

Есть ли разница в эффективности между:-

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 ответа

С точки зрения кодирования я бы определенно предпочел условное (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, я не уверен, что мой тест верен. Но принимая результаты за чистую монету, "исключительный" подход несколько (~10%) медленнее. Если честно, я ожидал гораздо большей разницы.

С помощью try не несет никаких расходов, но если блок using создает слишком много исключений, вы должны попытаться просмотреть свой код.

Создание исключения в Java - очень медленная операция. Ожидайте, что выдача исключения обойдется вам примерно в 1-5 микросекунд. Почти все это время уходит на заполнение стека потока исключений. Чем глубже трассировка стека, тем больше времени потребуется для его заполнения.

для более подробной информации читайте здесь

Исключения - для исключительных ситуаций, которые вы хотите передать обратно вызывающей стороне. Не полагайтесь на исключения во время нормальной работы.

Я бы просто написал ваш код как:

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

Но чтобы ответить на ваш вопрос: try-catch-finally реализован в Java с использованием автономных таблиц исключений, и, как таковой, когда не генерируется исключение, это ноль издержек.

Вот как выглядит байт-код ваших двух функций:

  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 ситуации.

Если есть сомнения, отметьте это.

Другие вопросы по тегам