Пытается ли улов снизить эффективность?
Есть ли разница в эффективности между:-
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
ситуации.
Если есть сомнения, отметьте это.