2010-01-20 9 views
12

Я ценю, что все, что может быть сделано с помощью статуса switch, может выполняться с помощью инструкции if else.Когда использовать оператор switch в Java

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

+3

Если вы не хотите, чтобы мозоль-офф следующего разработчика, который должен поддерживать ваши коды 100x, если/else. –

+6

Я не знаю ... Думаю, я был бы так же раздражен 100 случаями в переключателе. :-) Пахнет плохим дизайном. – cjstehno

+0

Всегда, потому что быстрее: http://stackoverflow.com/questions/2086529 –

ответ

15

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

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

+2

FWIW, строки в операторах switch находятся в JDK7 – basszero

+0

@basszero: Это окончательный? Последнее, что я знаю, еще предстоит решить. – BalusC

4

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

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

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

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

т.д.

чем

if (i == 1) { 

} else if (i == 2) { 

}... 

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

+1

Я не на 100% убежден, что его эстетически более приятный - отчасти зависит от того, к чему вы привыкли. Проблема с коммутатором в том, что так легко забыть оператор break. – Dan

+1

@ Dan: Я привык всегда печатать «случай» и «ломать» в парах. Таким образом я никогда их не забываю. Но я согласен, что это не слишком приятно. Хотя, вероятно, не так много людей спорят на этом фронте :-) – Joey

+0

Согласен, по крайней мере, с if-else у вас есть синтаксис, который поможет вам - возможно, по умолчанию в коммутаторе должно было быть разбито после того, как был сопоставлен случай. – Dan

1

Прежде всего, оператор switch должен использоваться. Если переключатель основан на значении переменной, то он может использоваться. Если он основан на сложном логическом выражении AND/OR/NOT, которое меняется для каждого условия, то вы не можете использовать его вообще.

Это, если это применимо, и есть как минимум 2 случая, тогда я использую переключатель. Это более легко расширяемое, удобное для чтения и проверки.

0

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

0

Как и в других языках, таких как C или C++, операторы switch полезны, если вы хотите сравнить данную переменную со списком возможных значений и выполнить действие в зависимости от этих значений. Это более сложное, чем выражения else.

5

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

2

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

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

+0

Согласовано, все, что требует * диапазонов * значений, требует инструкции 'if'. –

3

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

+0

Я полностью согласен с вашей точкой использования операторов switch для перекрывающегося кода. На мой взгляд, инструкции switch требуют совершенно иного способа мышления для операторов «if..else if». Вы используете «случай :», чтобы выбрать начальную точку для случая в блоке кода, а затем вы используете break для запуска совершенно нового блока кода. Единственная проблема для этого способа мышления для меня состоит в том, что у вас не может быть дублированных случаев для каждого «блока прерывания». –

-1

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

  • он ограничивается примитивными типами и перечислений
  • вы должны помнить «перерыв», что может привести к не столь очевидных ошибок

Часто switch является признаком плохого дизайна OO, потому что вам лучше использовать полиморфизм.

Единственное возможное преимущество переключателя в том, что оно более читаемо. Но

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

более читаемым, чем это:

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

Я бы сказал: нет! И у вас не было бы недостатков переключателя.

Мое предложение: Старайтесь избегать переключения.

+5

. Вы, вероятно, не будете переключаться на два случая. Вместо того, чтобы избегать переключения, научиться эффективно использовать его - это лучшая идея, и именно этот вопрос задается вопросом. – Armstrongest

+0

Полностью согласен, если ваш код OO для записи вам очень не нужен для операторов switch. –

10

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

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 
} 

Это также проще для вас (или другого программиста), чтобы разделить и корпуса.

+1

С другой стороны, вам нужно указать каждое значение для обычных случаев вместо того, чтобы писать 'else if (i% 2 == 0)'. Иногда я пропускаю VB 'Select Case' :-) – Joey

1

Переключатель и перечисления.

Если значение перечисления, которое вы тестируете, может быть законным null по любой причине, поместив его в оператор switch, вы получите исключение NullPointerException. Не смотря на байт-код, это несколько озадачивает, что он это сделает.

Объяснение: перечисления представляют собой синтаксический сахар, введенный в 1.5. Оператор switch по-прежнему работает с хорошими именами, но значения, которые он использует, являются ординалами, назначенными для перечисления. Чтобы получить порядковый номер, значение перечисления ДОЛЖНО быть не нулевым.

if statement, с другой стороны, был бы рад принять null за значение перечисления и просто пропустить тест без NPE.

1

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

3

Я предлагаю простое правило:

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

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

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

+0

Полностью согласен, за исключением забытого' break' по сравнению с забытым 'else'. Я не думаю, что можно утверждать, что он более вероятен, чем другой. – Kirby

1

Я всегда находил, что инструкция оператора java не такая мощная, насколько мне нужно. В его last release lambdaj implements it с умным использованием закрытия и 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); 
+0

+1: Это выглядит круто. Меня удивляет, что оператор switch Java остается настолько слабым: вы даже не можете включить Integer. Выражение слова Scala намного мощнее. Heck, Cobol (19) 85-ая оценка EVALUATE значительно более полезна. –

1

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

Если одно из условий является доминирующим, то 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; 
    } 

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

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

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

0

Я согласен с x4u's answer.

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

Например, я только что наткнулся на этот код, который имеет switch на строку type, а затем проверяет вторую строку extension, используя в обоих case заявления об if.

public abstract class Temp { 

    boolean valid; 

    public Temp() { 
     String type = getType(); 
     String extension = getFilenameExtension(); 
     switch(type) { 
      case "Image File": { 
       if(!".jpg".equals(extension) && !".png".equals(extension)) { 
        warnWrongImageFormat(); 
        valid = false; 
       } 
       break; 
      } 
      case "Zip File": { 
       if(!".zip".equals(extension)) { 
        warnWrongZipFormat(); 
        valid = false; 
       } 
       break; 
      } 
      default: { 
       valid = true; 
       break; 
      } 
     } 
    } 

    abstract String getType(); 
    abstract String getFilenameExtension(); 
    abstract void warnWrongImageFormat(); 
    abstract void warnWrongZipFormat(); 
} 

Вместо этого он намного чище и менее сложным, чтобы уменьшить это один ifelse

public abstract class Temp { 

    boolean valid; 

    public Temp() { 
     String type = getType(); 
     String extension = getFilenameExtension(); 
     valid = true; 
     if("Image File".equals(type) && !".jpg".equals(extension) && !".png".equals(extension)) { 
      warnWrongImageFormat(); 
      valid = false; 
     } 
     else if("Zip File".equals(type) && !".zip".equals(extension)) { 
      warnWrongZipFormat(); 
      valid = false; 
     } 
    } 

    abstract String getType(); 
    abstract String getFilenameExtension(); 
    abstract void warnWrongImageFormat(); 
    abstract void warnWrongZipFormat(); 
}