Когда использовать оператор switch в Java - PullRequest
13 голосов
/ 20 января 2010

Я ценю, что все, что может быть сделано с помощью параметра switch, может быть сделано оператором if else.

Но существуют ли стилистические правила, когда нужно использовать переключатель, а не как статут?

Ответы [ 16 ]

16 голосов
/ 20 января 2010

Ну, по моему мнению, switch во многих случаях кажется "легче", чем лестница if / else if. По сути, у вас не так много синтаксиса с фигурными скобками и скобками на пути вашего кода. При этом switch наследует синтаксис Си. Это означает, что у вас есть break и только одна область видимости для переменных, если вы не вводите новые блоки.

Тем не менее, компилятор может оптимизировать операторы switch в таблицу поиска и выполнять проверку литералов во время компиляции при работе с перечислениями. Итак, я бы предположил, что обычно предпочтительнее использовать switch вместо if / else if, если вы имеете дело с числовыми типами или типами enum.

11 голосов
/ 20 января 2010

Переключатель имеет одно преимущество, когда речь идет о ясности:

switch (i) {
  case 1:
    // do something
    break;
  case 2:
  case 4:
    // do something
    break;
  case 5:
    // do something
    break;
}

Если код для 2 и 4 идентичен, это может быть более понятно, чем:

if ( i == 1 ) {
  // do something
}
if ( (i == 2) || (i == 4) ) {
  // do something
}
if ( (i == 5 ) {
  // do something
}

Вам (или другому программисту) также легче разделить случаи 2 и 4 .

5 голосов
/ 20 января 2010

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

4 голосов
/ 20 января 2010

Вы используете оператор switch, когда включаете разные значения типов примитивов / перечислений / оболочек. (И не все типы примитивов / оболочек, а только поддерживаемые - byte, short, char, int).

Если / else обрабатывает все остальное.

Например, эстетически приятнее сказать:

int i = getValueOfI();
switch (i) {
  case 1:
    // do something
    break;
  case 2:
    // do something
    break;

и т.д.

1010 * чем *

if (i == 1) {

} else if (i == 2) {

}...

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

3 голосов
/ 20 января 2010

Я бы предложил простое правило:

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

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

Виртуальные машины Java фактически поддерживают два различных типа переключателей: переключатель таблиц и инструкцию lookupswitch. Табличный переключатель генерируется компилятором, если все case константы лежат в узком диапазоне, в противном случае он генерирует переключатель поиска. Для больших операторов switch во многих случаях табличный переключатель более эффективен, чем переключатель поиска. Переключатель поиска обычно реализуется с помощью бинарного поиска.

3 голосов
/ 20 января 2010

Лично я использую, чтобы найти обе конструкции слишком процедурными. Хотя это может считаться ОО-экстеризмом, я использую Карту, содержащую экземпляры внутреннего интерфейса для каждого случая if. Это позволяет лучше изолировать код, я думаю. Однако, чтобы полностью ответить на ваш вопрос, я использую переключатели только в тех случаях, когда у меня действительно перекрываются случаи (я не использую операторы break). К сожалению, это действительно не поддерживаемый блок кода.

2 голосов
/ 20 января 2010

Для меня есть два фактора:

Удобочитаемость и хотите ли вы что-то решить, используя диапазоны значений или условий (в выражениях switch вы можете использовать только одно целое или перечисляемое значение).

1 голос
/ 13 сентября 2012

Ответ зависит от того, что именно вы делаете, а также от распределения выбора.

Если доминирует одно условие, тогда уместно if / then.

if (i == 1){
  //do something
}else if (i == 2){
   // do something else
}

Если условия распределены равномерно, оптимизация в компиляторе даст преимущество в производительности. Эта разница в производительности становится более заметной по мере увеличения числа возможных вариантов.

switch (i) {
  case 1:
     // do something
     break;
  case 2:
     // do something else
     break;
  ....
  case N: 
     // do yet something else
     break;
  }

Тем не менее, если производительность НЕ важна, выбирайте наиболее удобочитаемый (поддерживаемый и простой в написании) вариант.

Если, с другой стороны, если ваш код находится в горячей точке, где важна производительность, вы должны пойти с коммутатором.

Для «чрезвычайно больших» условий пример лямбдадж-переключателя Марио действительно классный, и при тщательной инициализации получится очень высокая производительность. Кодирование очень похоже на то, что генерирует оптимизатор. Я бы определил «чрезвычайно большой», когда число опций является большим или достаточно сложным, чтобы его стоило ввести все это, и стоит путаницы в поддержке с тем, когда последующий разработчик пытается пройти код. (Прокомментируйте свой код, объяснив, почему у вас все это есть!).

1 голос
/ 28 марта 2010

Я всегда обнаруживал, что оператор переключения Java не так силен, как мне нужно. В своем последнем выпуске lambdaj реализует его с умным использованием замыкания и совпадения Hamcrest.

Например, lambdaj Switcher позволяет реализовать шаблон стратегии. Предположим, вам нужно переключиться между тремя алгоритмами сортировки на основе некоторой характеристики списка, который нужно отсортировать. В частности, давайте предположим, что у нас есть специализированный алгоритм для строк:

public List<String> sortStrings(List<String> list) {
    // a sort algorithm suitable for Strings
}

еще один, который хорошо работает с небольшими списками, содержащими не более 100 элементов:

public List<T> sortSmallList(List<T> list) {
    // a sort algorithm suitable for no more than 100 items
}

и более универсальный:

public List<String> sort(List<String> list) {
    // a generic sort algorithm
}

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

Switcher<List<T>> sortStrategy = new Switcher<List<T>>()
    .addCase(having(on(List.class).get(0), instanceOf(String.class))), 
        new Closure() {{ of(this).sortStrings(var(List.class)); }})
    .addCase(having(on(List.class).size(), lessThan(100))), 
        new Closure() {{ of(this).sortSmallList(var(List.class)); }})
    .setDefault(new Closure() {{ of(this).sort(var(List.class)); }});

и сортируйте список, используя лучший из доступных алгоритмов, вызывая Switcher:

List<T> sortedList = sortStrategy.exec(list, list);
1 голос
/ 20 января 2010

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

...