Подтвердить что ты не робот

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

PMD сообщает мне

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

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

4b9b3361

Ответ 1

Потому что оператор 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

Ответ 2

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

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

Из веб-сайт PMD:

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

Ответ 3

Почему?

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

Почему 3?

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

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

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


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

Ответ 4

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

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

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