Java: производительность Enums против if-then-else - PullRequest
9 голосов
/ 07 февраля 2011

Мне не повезло, получая краткий ответ для этого сравнения с помощью Google, и вместо того, чтобы проводить свои собственные трудоемкие оценки, я решил сначала спросить.

Я вполне уверен, чтоОператор switch с использованием Enums будет работать быстрее, чем оператор if-then-else, хотя вопрос о том, является ли это заметной разницей, является другим вопросом.

Может ли кто-нибудь пролить свет на это для меня?


Спасибо за быстрые ответы, ребята, я буду помнить это для будущих проектов.

Ответы [ 6 ]

8 голосов
/ 07 февраля 2011

Да, это так, потому что в общем случае оператор 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

}

Что в обоих случаях выглядит довольно быстро.

Итак, выберите тот, который легче поддерживать.

7 голосов
/ 07 февраля 2011

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

1 голос
/ 07 февраля 2011

Мой ответ на этот вопрос такой же, как и всегда, на вопрос, является ли языковая конструкция X обычно быстрее языковой конструкции Y: общего ответа нет!

Может быть только конкретный ответ для определенных реализаций языка, например JVM на базе Hotspot-компилятора Oralce (формально Sun) или для JDK IBM на платформе Z или для OpenJDK в Linux, или ...

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

Поэтому я бы посоветовал выбирать языковые функции по их применимости и удобочитаемости в вашем контексте.

1 голос
/ 07 февраля 2011

Да, оператор switch будет в большинстве случаев выполняться быстрее, чем эквивалентный блок операторов if / else, потому что компилятор может выполнять больше оптимизаций (обычно блок switch компилируется в таблицу ветвлений, что практически невозможно сделать с помощью блок условностей.)

Я бы сказал, что они также более удобочитаемы и более удобны в обслуживании (за исключением использования аварийных случаев, против которых я бы посоветовал!)

То, заметно ли это быстрее, зависит от того, что вы определяете как заметное. Скорее всего, если вы не ищете что-то действительно конкретное, вы этого вообще не заметите, но я все равно поступлю так, потому что преимущество в удобочитаемости больше всего на свете (воспринимайте преимущество в скорости как бонус!)

1 голос
/ 07 февраля 2011

Я не знаю о более быстром, я думаю, они оба невероятно быстрые.

Я считаю, что переключение с помощью перечислений намного удобнее для чтения, чем блок multi-if / else

Но остерегайтесь пропущенных операторов разрыва !!

0 голосов
/ 07 февраля 2011

Теоретически оператор переключения может быть оптимизирован как один вычисленный скачок, тогда как цепочки if-then-else должны оставаться как отдельные сравнения.Я не знаю, действительно ли Java выполняет эту оптимизацию.

Независимо от того, переключатели лучше, чем цепочки if-then-else, с точки зрения читабельности и удобства обслуживания, поэтому используйте их в любом случае, если это возможно.

...