PMD
сообщает мне
Коммутатор с менее чем тремя ветвями неэффективен, используйте оператор if вместо этого.
Почему? Почему 3? Как они определяют эффективность?
PMD
сообщает мне
Коммутатор с менее чем тремя ветвями неэффективен, используйте оператор if вместо этого.
Почему? Почему 3? Как они определяют эффективность?
Потому что оператор 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
Несмотря на то, что при использовании коммутатора существует незначительная прибыль от использования по сравнению с использованием if-statement, эти выгоды были бы незначительными в большинстве случаев. И любой сканер исходного кода, достойный его соли, признает, что микро-оптимизации являются второстепенными по степени прозрачности кода.
Они говорят, что оператор if проще читать и занимает меньше строк кода, чем оператор switch, если коммутатор значительно короче.
Из веб-сайт PMD:
TooFewBranchesForASwitchStatement: Операторы Switch, как правило, используются для поддержки сложного поведения ветвления. Использование переключателя только для нескольких случаев не рекомендуется, так как переключатели не так просто понять, как если бы тогда были утверждения. В этих случаях используйте инструкцию the-then для повышения удобочитаемости кода.
Почему?
Различные последовательности инструкций используются, когда код (наконец) скомпилирован в собственный код компилятором JIT. Коммутатор реализуется последовательностью нативных инструкций, которые выполняют непрямую ветвь. (Последовательность, как правило, загружает адрес из таблицы и затем переходит к этому адресу.) Если /else реализовано как инструкции, которые оценивают условие (возможно, инструкцию сравнения), за которым следует инструкция условного перехода.
Почему 3?
Это эмпирическое наблюдение, я полагаю, основываясь на анализе сгенерированных инструкций на основе собственного кода и/или бенчмаркинга. (Или, возможно, нет. Чтобы быть абсолютно уверенным, вам нужно попросить автора (ов) этого правила PMD, как они получили это число.)
Как они определяют эффективность?
Время выполнения инструкций.
Я лично принял бы проблему с этим правилом... или, точнее, с сообщением. Я думаю, это должно сказать, что оператор if / else
проще и читабельнее, чем коммутатор с 2 случаями. Проблема эффективности является вторичной и, вероятно, не имеет значения.
Я полагаю, что это связано с тем, что переключатель, и if/else компилируется.
Скажем, для обработки оператора switch требуется 5 вычислений. Скажем, оператор if принимает два вычисления. Менее 3 опций в вашем коммутаторе равнялись бы 4 вычислениям в ifs vs 5 в коммутаторах. Однако служебные данные остаются постоянными в коммутаторе, поэтому, если у него есть 3 варианта, ifs будет обрабатываться 3 * 2, а 5 для переключателя.
Выгоды при просмотре миллионов вычислений крайне незначительны. Это скорее вопрос "это лучший способ сделать это", а не все, что может повлиять на вас. Это будет делать только то, что циклически действует на эту функцию миллионы раз в совершенно итерации.