Java: производительность Enums против if-then-else
Мне не повезло получить краткий ответ для этого сравнения с помощью Google, и вместо того, чтобы проводить свои собственные трудоемкие оценки, я подумал, что сначала спрошу.
Я вполне уверен, что оператор switch, использующий Enums, будет работать быстрее, чем оператор if-then-else, хотя вопрос о том, является ли это заметной разницей, - другой вопрос.
Может ли кто-то пролить свет на это для меня?
Спасибо за быстрые ответы, ребята, я буду помнить это для будущих проектов.
6 ответов
Да, это так, потому что в общем случае оператор switch работает быстрее, чем цепочка if / else.
Хотя сгенерированный байт-код не всегда является определяющим источником для сравнения производительности, вы можете проверить его, чтобы иметь более полное представление.
Например, этот код:
class A {
enum N { ONE, TWO, THREE }
void testSwitch( N e ) {
switch( e ) {
case ONE : x(); break;
case TWO : x(); break;
case THREE : x(); break;
}
}
void testIf( Enum e ) {
if( e == N.ONE ) { x(); }
else if( e == N.TWO ) { x(); }
else if( e == N.THREE ) { x(); }
}
void x(){}
}
Создает следующее:
Compiled from "A.java"
class A extends java.lang.Object{
A();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
void testSwitch(A$N);
Code:
0: getstatic #2; //Field A$1.$SwitchMap$A$N:[I
3: aload_1
4: invokevirtual #3; //Method A$N.ordinal:()I
7: iaload
8: tableswitch{ //1 to 3
1: 36;
2: 43;
3: 50;
default: 54 }
36: aload_0
37: invokevirtual #4; //Method x:()V
40: goto 54
43: aload_0
44: invokevirtual #4; //Method x:()V
47: goto 54
50: aload_0
51: invokevirtual #4; //Method x:()V
54: return
void testIf(java.lang.Enum);
Code:
0: aload_1
1: getstatic #5; //Field A$N.ONE:LA$N;
4: if_acmpne 14
7: aload_0
8: invokevirtual #4; //Method x:()V
11: goto 39
14: aload_1
15: getstatic #6; //Field A$N.TWO:LA$N;
18: if_acmpne 28
21: aload_0
22: invokevirtual #4; //Method x:()V
25: goto 39
28: aload_1
29: getstatic #7; //Field A$N.THREE:LA$N;
32: if_acmpne 39
35: aload_0
36: invokevirtual #4; //Method x:()V
39: return
void x();
Code:
0: return
}
Который кажется довольно быстрым в обоих случаях.
Итак, выберите тот, который легче поддерживать.
Просто придерживайтесь наиболее читабельного и понятного кода, который вы можете придумать, я уверен, что вы потеряли все время, потраченное на оптимизацию производительности, ища этот ответ. Подобные микрооптимизации редко стоят того и могут легко привести к более сложному, чем нужно, коду.
Я не знаю, быстрее, я думаю, они оба невероятно быстрые.
Я считаю, что переключение с перечислениями намного удобнее для чтения, чем блок multi-if/else
Но остерегайтесь пропущенных операторов перерыва!
Да, оператор switch будет почти всегда выполняться быстрее, чем эквивалентный блок операторов if / else, потому что компилятор может выполнять больше оптимизаций (обычно блок switch компилируется в таблицу ветвлений, что практически невозможно сделать с блоком условные.)
Я бы сказал, что они также более читабельны и более удобны в обслуживании (за исключением использования аварийных случаев, против которых я бы посоветовал!)
Что касается того, заметно ли это быстрее, зависит от того, что вы определяете как заметное. Скорее всего, если вы не ищете что-то действительно конкретное, вы этого вообще не заметите, но я все равно поступлю так, потому что преимущество в удобочитаемости больше, чем что-либо еще (рассматривайте преимущество в скорости как бонус!)
Мой ответ на этот вопрос такой же, как и всегда, на вопрос, является ли языковая конструкция X в целом быстрее, чем языковая конструкция Y: общего ответа нет!
Может быть только конкретный ответ для определенных реализаций языка, например, для JVM на базе Hotspot-компилятора Oralce (формально Sun) или для JDK IBM на платформе Z или для OpenJDK в Linux, или...
Таким образом, единственный способ дать содержательный ответ на ваш вопрос - сделать правильный тест. Остерегайтесь микро-тестов, они чаще ошибаются, чем правильно, см., Например, Как не писать микро-тесты. Если вы все еще хотите узнать об использовании этого вопроса, рамки описаны здесь.
Поэтому я бы посоветовал выбирать языковые функции по их применимости и удобочитаемости в вашем контексте.
Теоретически оператор переключения может быть оптимизирован как отдельный вычисляемый скачок, тогда как цепочки "если-то-иначе" должны оставаться как отдельные сравнения. Я не знаю, действительно ли Java выполняет эту оптимизацию.
Независимо от этого, переключатели лучше, чем цепочки "если-то-еще", с точки зрения удобочитаемости и удобства обслуживания, поэтому, если возможно, используйте их.