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

Когда использовать оператор switch в Java

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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.

Ответ 3

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

Ответ 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.

Ответ 5

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

Ответ 6

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

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

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

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

Ответ 7

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

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

Ответ 8

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

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

Ответ 9

Переключение и перечисление.

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

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

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

Ответ 10

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

Ответ 11

Я всегда обнаружил, что оператор 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)); }});

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

List<T> sortedList = sortStrategy.exec(list, list);

Ответ 12

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

Если одно условие является доминантным, то if/тогда подходит.

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;
  }

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

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

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

Ответ 13

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

Ответ 14

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

Ответ 15

Я согласен с ответом x4u.

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

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

 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();
}

Вместо этого гораздо проще и менее сложно уменьшить это до одного if else

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();
}

Ответ 16

Коммутатор имеет два недостатка:

  • он ограничен примитивными типами и перечислениями
  • вам нужно запомнить "break", что может привести к не столь очевидным ошибкам.

Часто переключатель является признаком плохого дизайна 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

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

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