Использование двух значений для одного оператора переключателя


296

В моем коде программа делает что-то в зависимости от текста, введенного пользователем. Мой код выглядит так:

switch (name) {
        case text1: {
            //blah
            break;
        }
        case text2: {
            //blah
            break;
        }
        case text3: {
            //blah
            break;
        }
        case text4: {
            //blah
            break;
        }

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

case text1||text4: {
            //blah
            break;
        }

Я знаю, что ||оператор не будет работать в операторе case, но есть ли что-то подобное, что я могу использовать.


32
Основной вопрос делает его более подходящим для голосов, если это не дубликат, поскольку он широко полезен. И это то, что не происходило со мной настолько, насколько это возможно, но теперь, когда я осознал это, это было очевидно. В общем, довольно крутые вопросы и ответы
Ричард Тингл,

1
@RichardTingle - вы знакомы с устройством Даффа - en.wikipedia.org/wiki/Duff%27s_device
user93353

4
«Почему так много голосов? Ищите« java switch »в Интернете и прочитайте одно из тысячи объяснений». <- что ты думаешь я делал?
Брендан,

4
Я буквально искал «несколько случаев в одной строке Java», и этот Q & A был первым результатом.
Domenix

1
Демонстрация переключения в выбранном ответе может быть перефразирована теперь, когда JDK-12 интегрировал JEP-325. :)
Наман

Ответы:


556

Вы можете использовать оба CASEутверждения следующим образом.

  case text1: 
  case text4:{
            //blah
            break;
        }

СМОТРИТЕ НАСТОЯЩИЙ ПРИМЕР: Пример кода вычисляет количество дней в конкретном месяце:

class SwitchDemo {
    public static void main(String[] args) {

        int month = 2;
        int year = 2000;
        int numDays = 0;

        switch (month) {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                numDays = 31;
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                numDays = 30;
                break;
            case 2:
                if (((year % 4 == 0) && 
                     !(year % 100 == 0))
                     || (year % 400 == 0))
                    numDays = 29;
                else
                    numDays = 28;
                break;
            default:
                System.out.println("Invalid month.");
                break;
        }
        System.out.println("Number of Days = "
                           + numDays);
    }
}

Это вывод из кода:

Number of Days = 29

ПРОВАЛИВАТЬСЯ:

Еще один интересный момент - это заявление о разрыве. Каждый оператор break завершает вмещающий оператор switch. Поток управления продолжается с первого оператора, следующего за блоком переключателей. Операторы break необходимы, потому что без них операторы в блоках переключателей fall through: все операторы после совпадающей метки регистра выполняются последовательно, независимо от выражения последующих меток регистра, до тех пор, пока не встретится оператор break.

ПРИМЕР КОДА:

public class SwitchFallThrough {

    public static void main(String[] args) {
        java.util.ArrayList<String> futureMonths =
            new java.util.ArrayList<String>();

        int month = 8;

        switch (month) {
            case 1:  futureMonths.add("January");
            case 2:  futureMonths.add("February");
            case 3:  futureMonths.add("March");
            case 4:  futureMonths.add("April");
            case 5:  futureMonths.add("May");
            case 6:  futureMonths.add("June");
            case 7:  futureMonths.add("July");
            case 8:  futureMonths.add("August");
            case 9:  futureMonths.add("September");
            case 10: futureMonths.add("October");
            case 11: futureMonths.add("November");
            case 12: futureMonths.add("December");
            default: break;
        }

        if (futureMonths.isEmpty()) {
            System.out.println("Invalid month number");
        } else {
            for (String monthName : futureMonths) {
               System.out.println(monthName);
            }
        }
    }
}

Это вывод из кода:

August
September
October
November
December

Использование строк в выражениях переключателя

В Java SE 7 и более поздних версиях вы можете использовать объект String в выражении оператора switch. В следующем примере кода отображается номер месяца на основе значения строки с именем month:

public class StringSwitchDemo {

    public static int getMonthNumber(String month) {

        int monthNumber = 0;

        if (month == null) {
            return monthNumber;
        }

        switch (month.toLowerCase()) {
            case "january":
                monthNumber = 1;
                break;
            case "february":
                monthNumber = 2;
                break;
            case "march":
                monthNumber = 3;
                break;
            case "april":
                monthNumber = 4;
                break;
            case "may":
                monthNumber = 5;
                break;
            case "june":
                monthNumber = 6;
                break;
            case "july":
                monthNumber = 7;
                break;
            case "august":
                monthNumber = 8;
                break;
            case "september":
                monthNumber = 9;
                break;
            case "october":
                monthNumber = 10;
                break;
            case "november":
                monthNumber = 11;
                break;
            case "december":
                monthNumber = 12;
                break;
            default: 
                monthNumber = 0;
                break;
        }

        return monthNumber;
    }

    public static void main(String[] args) {

        String month = "August";

        int returnedMonthNumber =
            StringSwitchDemo.getMonthNumber(month);

        if (returnedMonthNumber == 0) {
            System.out.println("Invalid month");
        } else {
            System.out.println(returnedMonthNumber);
        }
    }
}

Выход из этого кода 8.

ИЗ Java Docs


о хорошо Это было легко. Не знал, что смогу это сделать
Анкуш

18
Стоит отметить, что эта языковая функция называется Fallthrough. Случаи без breakобычно присоединяются к следующему блоку случаев, который визуально находится ниже, следовательно, проваливается .
Император Орионий

5
@ Kobor42 сначала узнайте, как разговаривать на общедоступных сайтах. Любая помощь поможет вам. Спасибо
PSR

1
@ Kobor42 Как насчет того, почему вы использовали это форматирование? Размещение случаев по горизонтали делает код менее читабельным и обычно считается плохой практикой [Ссылка необязательна, но желательна]. Я всегда чувствовал, что операторы switch являются особенно читаемым форматом, но представлены таким образом, что они теряют все это.
Ричард Тингл

2
Демонстрацию коммутатора можно перефразировать, поскольку в JDK-12 встроен JEP-325. :)
Наман


27

Эти caseзначения являются просто Codeless «GOTO» точек , которые могут одни и те же точки входа:

case text1:
case text4: 
    //blah
    break;

Обратите внимание, что фигурные скобки являются избыточными.


@ триг лол. В последнее время я часто этим занимаюсь - обвиняю iPhone в наборе большого пальца. Приветствия
Богемский


15

С интеграцией JEP 325: Выражения коммутатора (Preview) в ранние сборки доступа JDK-12 теперь можно использовать новую форму метки коммутатора, как: -

case text1, text4 -> {
     //blah
} 

или перефразировать демо из одного из ответов , например:

public class RephraseDemo {

    public static void main(String[] args) {
        int month = 9;
        int year = 2018;
        int numDays = 0;

        switch (month) {
            case 1, 3, 5, 7, 8, 10, 12 ->{
                numDays = 31;
            }
            case 4, 6, 9, 11 ->{
                numDays = 30;
            }
            case 2 ->{
                if (((year % 4 == 0) &&
                        !(year % 100 == 0))
                        || (year % 400 == 0))
                    numDays = 29;
                else
                    numDays = 28;
            }
            default ->{
                System.out.println("Invalid month.");

            }
        }
        System.out.println("Number of Days = " + numDays);
    }
}

Вот как вы можете попробовать - скомпилируйте функцию предварительного просмотра JDK12 с Maven


6

Скобки не нужны. Просто сделать

case text1:
case text4:
  doSomethingHere();
  break;
case text2:
  doSomethingElse()
  break;

Если кому-то интересно, это называется падением случая. Способность сделать это является причиной, по которой break;необходимо завершить рассмотрение дел. Для получения дополнительной информации см. Статью в Википедии http://en.wikipedia.org/wiki/Switch_statement .


5

Эти fallthroughответы на другие являются хорошими.

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

В приведенном ниже примере регистр 'text1' и регистр 'text4' ведут себя одинаково:

switch (name) {
        case text1: {
            method1();
            break;
        }
        case text2: {
            method2();
            break;
        }
        case text3: {
            method3();
            break;
        }
        case text4: {
            method1();
            break;
        }

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


1
Это не более приемлемо, если text1и text4ПОЧТИ ОПРЕДЕЛИТЕ то же самое, независимо от будущих изменений. Если они всегда должны быть связаны, внесение изменений в регистр text1(означающее изменение метода, который он вызывает) потребует изменения text4. В этом случае это явно не более ремонтопригодно. Это зависит от ситуации.
Ник Фриман

1
Я скажу, что этот метод, вероятно, должен в любом случае сочетаться с другим способом, поскольку операторы switch не являются (IMHO) самой красивой структурой программирования.
Ник Фриман



4

Значения регистра - это просто точки без перехода "goto", которые могут использовать одну и ту же точку входа:

case text1:
case text4: {
// Делаем что-нибудь
break;
}

Обратите внимание, что фигурные скобки являются избыточными.


1

JEP 354. Выражения-переключатели (предварительный просмотр) в JDK-13 и JEP-361. Выражения-переключатели (стандартный) в JDK-14 расширят оператор switch, чтобы его можно было использовать в качестве выражения .

Теперь вы можете:

  • напрямую назначить переменную из выражения switch ,
  • используйте новую форму метки переключателя ( case L ->):

    Код справа от метки переключателя «case L ->» ограничен выражением, блоком или (для удобства) оператором throw.

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

    Чтобы получить значение из выражения switch, breakоператор with value отбрасывается в пользу yieldоператора.

Таким образом, демонстрация одного из ответов может выглядеть так:

public class SwitchExpression {

  public static void main(String[] args) {
      int month = 9;
      int year = 2018;
      int numDays = switch (month) {
        case 1, 3, 5, 7, 8, 10, 12 -> 31;
        case 4, 6, 9, 11 -> 30;
        case 2 -> {
          if (java.time.Year.of(year).isLeap()) {
            System.out.println("Wow! It's leap year!");
            yield 29;
          } else {
            yield 28;
          }
        }
        default -> {
          System.out.println("Invalid month.");
          yield 0;
        }
      };
      System.out.println("Number of Days = " + numDays);
  }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.