Эффективность: операторы переключения вместо операторов if

PMD говорит мне

Переключатель с менее чем 3 ветвями неэффективен, вместо этого используйте оператор if.

Это почему? Почему 3? Как они определяют эффективность?


person James Raitsev    schedule 05.05.2012    source источник
comment
PMD сканирует исходный код Java и ищет потенциальные проблемы, такие как возможные ошибки, мертвый код, неоптимальный код, чрезмерно сложные выражения и повторяющийся код. (Наведите курсор на теги)   -  person Chords    schedule 05.05.2012
comment
Он также должен сканировать себя на наличие грамматики. Меньше должно быть меньше. :)   -  person yshavit    schedule 05.05.2012
comment
@jmort253 jmort253 Обновлен вопрос, чтобы включить ссылку   -  person James Raitsev    schedule 05.05.2012
comment
@yshavit подходит меньше, и поэтому меньше, в этом случае достаточно коннотации. cracked.com/blog/   -  person Mike McMahon    schedule 05.05.2012
comment
Не навязывай мне свою дескриптивистскую грамматику, @MikeMcMahon! Мне нравится моя грамматика, как мне нравятся мои ледники: старые, замерзшие и движущиеся как можно медленнее.   -  person yshavit    schedule 05.05.2012
comment
обязательная преждевременная оптимизация - корень всех зол и т.д.   -  person zzzzBov    schedule 05.05.2012
comment
Я бы использовал структуру Java, которую легче всего читать, независимо от эффективности. Скорее всего, если вам нужно оптимизировать, это не будет в этом разделе. Кроме того, если вам нужна производительность, Java — неправильный язык.   -  person Tony Ennis    schedule 05.05.2012


Ответы (4)


Поскольку оператор switch скомпилирован с двумя специальными инструкциями JVM, lookupswitch и tableswitch. Они полезны при работе с большим количеством случаев, но вызывают накладные расходы, когда у вас всего несколько ветвей.

Вместо этого оператор if/else компилируется в типичные цепочки je jne ..., которые быстрее, но требуют гораздо большего количества сравнений при использовании в длинной цепочке ветвей.

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

Практический пример:

switch (i)
{
  case 1: return "Foo";
  case 2: return "Baz";
  case 3: return "Bar";
  default: return null;
}

компилируется в:

L0
 LINENUMBER 21 L0
 ILOAD 1
 TABLESWITCH
   1: L1
   2: L2
   3: L3
   default: L4
L1
 LINENUMBER 23 L1
FRAME SAME
 LDC "Foo"
 ARETURN
L2
 LINENUMBER 24 L2
FRAME SAME
 LDC "Baz"
 ARETURN
L3
 LINENUMBER 25 L3
FRAME SAME
 LDC "Bar"
 ARETURN
L4
 LINENUMBER 26 L4
FRAME SAME
 ACONST_NULL
 ARETURN

Пока

if (i == 1)
  return "Foo";
else if (i == 2)
  return "Baz";
else if (i == 3)
  return "Bar";
else
  return null;

компилируется в

L0
 LINENUMBER 21 L0
 ILOAD 1
 ICONST_1
 IF_ICMPNE L1
L2
 LINENUMBER 22 L2
 LDC "Foo"
 ARETURN
L1
 LINENUMBER 23 L1
FRAME SAME
 ILOAD 1
 ICONST_2
 IF_ICMPNE L3
L4
 LINENUMBER 24 L4
 LDC "Baz"
 ARETURN
L3
 LINENUMBER 25 L3
FRAME SAME
 ILOAD 1
 ICONST_3
 IF_ICMPNE L5
L6
 LINENUMBER 26 L6
 LDC "Bar"
 ARETURN
L5
 LINENUMBER 28 L5
FRAME SAME
 ACONST_NULL
 ARETURN
person Jack    schedule 05.05.2012

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

Они говорят, что оператор if проще для чтения и занимает меньше строк кода, чем оператор switch, если переключатель значительно короче.

С веб-сайта PMD:

TooFewBranchesForASwitchStatement: операторы Switch предназначены для поддержки сложного поведения ветвления. Использование переключателя только в нескольких случаях не рекомендуется, поскольку переключатели не так просты для понимания, как операторы "если-то". В этих случаях используйте оператор if-then, чтобы повысить читаемость кода.

person Tim Pote    schedule 05.05.2012
comment
Важность ясности намного превышает любые микрооптимизации. Никаких сомнений насчет этого. - person James Raitsev; 05.05.2012
comment
Приятно то, что в предупреждении указано, что это неэффективно, но они заявляют, что это просто связано с удобочитаемостью в документации. Хорошая согласованность.. - person Jack; 05.05.2012

Это почему?

Различные последовательности инструкций используются, когда код (окончательно) компилируется в машинный код JIT-компилятором. Переключение реализуется последовательностью собственных инструкций, выполняющих непрямой переход. (Последовательность обычно загружает адрес из таблицы, а затем переходит к этому адресу.) Оператор if/else реализуется как инструкции, которые оценивают условие (вероятно, инструкция сравнения), за которой следует инструкция условного перехода.

Почему 3?

Я предполагаю, что это эмпирическое наблюдение, основанное на анализе сгенерированных инструкций собственного кода и/или бенчмаркинге. (Или, возможно, нет. Чтобы быть абсолютно уверенным, вам нужно спросить автора (авторов) этого правила PMD, как они получили это число.)

Как они определяют эффективность?

Время, необходимое для выполнения инструкций.


Лично я бы не согласился с этим правилом... или, точнее, с сообщением. Я думаю, следует сказать, что оператор if / else проще и читабельнее, чем переключатель с двумя регистрами. Вопрос эффективности вторичен и, вероятно, не имеет значения.

person Stephen C    schedule 05.05.2012

Я считаю, что это связано со способом компиляции переключателя и if/else.

Скажем, для обработки оператора switch требуется 5 вычислений. Скажем, оператор if требует двух вычислений. Менее 3 вариантов в вашем коммутаторе будут равны 4 вычислениям в ifs против 5 в коммутаторах. Однако накладные расходы остаются постоянными в коммутаторе, поэтому, если у него есть 3 варианта, если будет обработано 3 * 2, а не 5 для коммутатора.

Прибыль, если смотреть на миллионы вычислений, крайне незначительна. Это скорее вопрос «это лучший способ сделать это», а не что-то, что может повлиять на вас. Это будет делаться только для чего-то, что повторяет эту функцию миллионы раз за тихую итерацию.

person thebarcodeproject    schedule 05.05.2012