Бросить и поймать исключение или использовать instanceof?
У меня есть исключение в переменной (не выбрасывается).
Какой лучший вариант?
Exception exception = someObj.getExcp();
try {
throw exception;
} catch (ExceptionExample1 e) {
e.getSomeCustomViolations();
} catch (ExceptionExample2 e) {
e.getSomeOtherCustomViolations();
}
или
Exception exception = someObj.getExcp();
if (exception instanceof ExceptionExample1) {
exception.getSomeCustomViolations();
} else if (exception instanceof ExceptionExample2) {
exception.getSomeOtherCustomViolations();
}
Ответы
Ответ 1
Я бы посоветовал использовать instanceof
, поскольку он, скорее всего, будет быстрее. Выброс исключения - сложная и дорогостоящая операция. JVM оптимизированы, чтобы быть быстрыми в случае, когда исключений не происходит. Исключения должны быть исключительными.
Обратите внимание, что метод throw
, вероятно, не будет компилироваться, как показано, если ваш тип исключения является проверенным исключением, компилятор будет жаловаться на то, что вы должны поймать этот тип или объявить его как брошенное (что соответствует предложению else { ... }
если вы используете метод instanceof
), который может или не может быть полезен, в зависимости от того, как вы хотите обрабатывать исключения, которые не являются одним из конкретных подтипов.
Ответ 2
Ненависть, чтобы взрывать все пузырьки, но с помощью try/catch
быстрее . Это не значит, что это "правильный" способ, но если производительность ключевая, то это победитель. Ниже приведены результаты следующей программы:
Выполнить 1
- Sub-run 1: Instanceof: 130 мс
- Sub-run 1: Try/catch: 118 мс
- Sub-run 2: Instanceof: 96 ms
- Sub-run 2: Try/catch: 93 ms
- Sub-run 3: Instanceof: 100 мс
- Подзапуск 3: Try/catch: 99 мс
Выполнить 2
- Sub-run 1: Instanceof: 140 ms
- Sub-run 1: Try/catch: 111 ms
- Sub-run 2: Instanceof: 92 мс
- Sub-run 2: Try/catch: 92 мс
- Sub-run 3: Instanceof: 105 мс
- Подзапуск 3: Try/catch: 95 мс
Выполнить 3
- Sub-run 1: Instanceof: 140 ms
- Подпрограмма 1: Try/catch: 135 мс
- Sub-run 2: Instanceof: 107 ms
- Sub-run 2: Try/catch: 88 ms
- Подзапуск 3: Instanceof: 96 мс
- Подзапуск 3: Try/catch: 90 мс
Тестовая среда
- Java: 1.7.0_45
- Mac OSX Mavericks
Дисконтирующие подвыборы прогрева каждого запуска метода instanceof
позволяют достичь в лучшем случае производительности try/catch
. Среднее (скидка согревания) метода instanceof
составляет 98 мс, а среднее значение try/catch
составляет 92 мс.
Обратите внимание, что я не изменял порядок, в котором каждый метод был протестирован. Я всегда тестировал блок instanceof
, затем блок try/catch
. Я хотел бы видеть другие результаты, противоречащие или подтверждающие эти выводы.
public class test {
public static void main (String [] args) throws Exception {
long start = 0L;
int who_cares = 0; // Used to prevent compiler optimization
int tests = 100000;
for ( int i = 0; i < 3; ++i ) {
System.out.println("Testing instanceof");
start = System.currentTimeMillis();
testInstanceOf(who_cares, tests);
System.out.println("instanceof completed in "+(System.currentTimeMillis()-start)+" ms "+who_cares);
System.out.println("Testing try/catch");
start = System.currentTimeMillis();
testTryCatch(who_cares, tests);
System.out.println("try/catch completed in "+(System.currentTimeMillis()-start)+" ms"+who_cares);
}
}
private static int testInstanceOf(int who_cares, int tests) {
for ( int i = 0; i < tests; ++i ) {
Exception ex = (new Tester()).getException();
if ( ex instanceof Ex1 ) {
who_cares = 1;
} else if ( ex instanceof Ex2 ) {
who_cares = 2;
}
}
return who_cares;
}
private static int testTryCatch(int who_cares, int tests) {
for ( int i = 0; i < tests; ++i ) {
Exception ex = (new Tester()).getException();
try {
throw ex;
} catch ( Ex1 ex1 ) {
who_cares = 1;
} catch ( Ex2 ex2 ) {
who_cares = 2;
} catch ( Exception e ) {}
}
return who_cares;
}
private static class Ex1 extends Exception {}
private static class Ex2 extends Exception {}
private static java.util.Random rand = new java.util.Random();
private static class Tester {
private Exception ex;
public Tester() {
if ( rand.nextBoolean() ) {
ex = new Ex1();
} else {
ex = new Ex2();
}
}
public Exception getException() {
return ex;
}
}
}
Ответ 3
Я настоятельно призываю вас фактически использовать простой объект для представления вашего "ограничения". Независимо от того, подходит ли вам интерфейс маркировки (например, Message
) или java.lang.String
. Исключения не предназначены для использования, как вы намереваетесь, даже если их можно заставить работать (я ожидал бы, что второй будет быстрее, но преждевременная оптимизация...).
Ответ 4
Вы также можете использовать полиморфизм, создав интерфейс для своих пользовательских исключений, который содержит метод getCustomViolation(). Тогда каждое пользовательское исключение реализует этот интерфейс и этот метод.