Зависит от того, как реализованы исключения. Самый простой способ - использовать setjmp и longjmp. Это означает, что все регистры процессора записываются в стек (что уже занимает некоторое время) и, возможно, необходимо создать некоторые другие данные ... все это уже происходит в операторе try. Оператор throw должен разматывать стек и восстанавливать значения всех регистров (и, возможно, других значений в виртуальной машине). Так что try и throw одинаково медленны, и это довольно медленно, однако, если исключение не выдается, выход из блока try в большинстве случаев не занимает времени (так как все помещается в стек, который очищается автоматически, если метод существует).
Sun и другие признали, что это, возможно, неоптимально, и, конечно, виртуальные машины становятся все быстрее и быстрее с течением времени. Есть еще один способ реализации исключений, который заставляет себя попробовать себя молниеносно (на самом деле вообще ничего не происходит для попытки - все, что должно произойти, уже сделано, когда класс загружается виртуальной машиной), и это делает бросок не столь медленным , Я не знаю, какая JVM использует эту новую, лучшую технику ...
... но вы пишете на Java, чтобы ваш код позже работал только на одной JVM в одной конкретной системе? Так как, если он когда-либо будет работать на любой другой платформе или любой другой версии JVM (возможно, любого другого поставщика), кто сказал, что они также используют быструю реализацию? Быстрый более сложный, чем медленный, и его нелегко реализовать во всех системах. Вы хотите остаться портативным? Тогда не полагайтесь на быстрые исключения.
Это также сильно влияет на то, что вы делаете в блоке try. Если вы открываете блок try и никогда не вызываете какой-либо метод из этого блока try, блок try будет очень быстрым, поскольку JIT может фактически обработать бросок как простое goto. Ему не нужно ни сохранять состояние стека, ни разматывать стек, если выбрасывается исключение (ему нужно только перейти к обработчикам перехвата). Тем не менее, это не то, что вы обычно делаете. Обычно вы открываете блок try и затем вызываете метод, который может вызвать исключение, верно? И даже если вы просто используете блок try в своем методе, какой это будет метод, который не вызывает никакой другой метод? Будет ли он просто рассчитать число? Тогда зачем вам исключения? Есть гораздо более элегантные способы регулирования потока программ. Практически для всего остального, кроме простой математики, вам придется вызывать внешний метод, и это уже разрушает преимущество локального блока try.
См. Следующий тестовый код:
public class Test {
int value;
public int getValue() {
return value;
}
public void reset() {
value = 0;
}
// Calculates without exception
public void method1(int i) {
value = ((value + i) / i) << 1;
// Will never be true
if ((i & 0xFFFFFFF) == 1000000000) {
System.out.println("You'll never see this!");
}
}
// Could in theory throw one, but never will
public void method2(int i) throws Exception {
value = ((value + i) / i) << 1;
// Will never be true
if ((i & 0xFFFFFFF) == 1000000000) {
throw new Exception();
}
}
// This one will regularly throw one
public void method3(int i) throws Exception {
value = ((value + i) / i) << 1;
// i & 1 is equally fast to calculate as i & 0xFFFFFFF; it is both
// an AND operation between two integers. The size of the number plays
// no role. AND on 32 BIT always ANDs all 32 bits
if ((i & 0x1) == 1) {
throw new Exception();
}
}
public static void main(String[] args) {
int i;
long l;
Test t = new Test();
l = System.currentTimeMillis();
t.reset();
for (i = 1; i < 100000000; i++) {
t.method1(i);
}
l = System.currentTimeMillis() - l;
System.out.println(
"method1 took " + l + " ms, result was " + t.getValue()
);
l = System.currentTimeMillis();
t.reset();
for (i = 1; i < 100000000; i++) {
try {
t.method2(i);
} catch (Exception e) {
System.out.println("You'll never see this!");
}
}
l = System.currentTimeMillis() - l;
System.out.println(
"method2 took " + l + " ms, result was " + t.getValue()
);
l = System.currentTimeMillis();
t.reset();
for (i = 1; i < 100000000; i++) {
try {
t.method3(i);
} catch (Exception e) {
// Do nothing here, as we will get here
}
}
l = System.currentTimeMillis() - l;
System.out.println(
"method3 took " + l + " ms, result was " + t.getValue()
);
}
}
Результат:
method1 took 972 ms, result was 2
method2 took 1003 ms, result was 2
method3 took 66716 ms, result was 2
Замедление из блока try слишком мало, чтобы исключить мешающие факторы, такие как фоновые процессы. Но блок catch убил все и сделал его в 66 раз медленнее!
Как я уже сказал, результат не будет таким плохим, если вы поместите try / catch и throw все в один и тот же метод (method3), но это специальная оптимизация JIT, на которую я бы не рассчитывал. И даже при использовании этой оптимизации бросок все еще довольно медленный. Так что я не знаю, что вы пытаетесь сделать здесь, но определенно есть лучший способ сделать это, чем использовать try / catch / throw.