Зачем нам нужно прерывать заявления о случаях?

Почему компилятор автоматически не помещает инструкции break после каждого блока кода в коммутаторе? Это по историческим причинам? Когда вам нужно выполнить несколько блоков кода?

Ответ 1

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

case 'A':
case 'B':
case 'C':
    doSomething();
    break;

case 'D':
case 'E':
    doSomethingElse();
    break;

и т.д.. Просто пример.

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

Ответ 2

Исторически, это потому, что case по существу определял label, также известный как целевая точка вызова goto. Оператор switch и связанные с ним случаи действительно представляют собой многовекторную ветвь с множеством потенциальных точек входа в поток кода.

Все, что было сказано, было отмечено почти бесконечное количество раз, что break почти всегда является поведением по умолчанию, которое вы предпочитаете в конце каждого случая.

Ответ 3

Java приходит из C, и это синтаксис из C.

Иногда вам нужно, чтобы несколько операторов case имели только один путь выполнения. Ниже приведен образец, который расскажет вам, сколько дней в месяц.

class SwitchDemo2 {
    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);
    }
}

Ответ 4

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

Например, допустим, что вы хотите выполнить определенное действие для всех случаев, но в определенном случае вы хотите сделать это действие плюс что-то еще. Использование оператора switch с провалом сделает его довольно простым.

switch (someValue)
{
    case extendedActionValue:
        // do extended action here, falls through to normal action
    case normalActionValue:
    case otherNormalActionValue:
        // do normal action here
        break;
}

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

Ответ 5

Я думаю, что это ошибка. В качестве языковой конструкции так же легко иметь break как значение по умолчанию и вместо этого имеет ключевое слово fallthrough. Большая часть кода, который я написал и прочитал, имеет прерывание после каждого случая.

Ответ 6

Почему компилятор автоматически не помещает инструкции break после каждого блока кода в коммутаторе?

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

Это по историческим причинам? Когда вам нужно выполнить несколько блоков кода?

Это в основном для совместимости с C и, возможно, является древним взломом из старых дней, когда goto ключевые слова бродили по земле. Разумеется, это дает некоторые удивительные вещи, такие как Duff Device, но есть ли это в его пользу или против... аргумент в лучшем случае.

Ответ 7

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

case THIS:
case THAT:
{
    code;
    break;
}

Или вы можете делать такие вещи, как:

case THIS:
{
   do this;
}
case THAT:
{
   do that;
}

В каскадной форме.

На самом деле ошибка/путаница, если вы спросите меня.

Ответ 8

Java является производным от C, чье наследие включает в себя метод, известный как Duff Device. Это оптимизация, которая опирается на тот факт, что контроль проходит от одного случая к другому, в отсутствие оператора break;. К тому времени, когда C был стандартизирован, было много такого кода, как "в дикой природе", и было бы контрпродуктивно менять язык, чтобы разрушить такие конструкции.

Ответ 9

Что касается исторической записи, Тони Хоар изобрел деловое выражение в 1960-х годах во время "структурированного программирования". Утверждение дела Тони поддерживало несколько ярлыков в каждом случае и автоматический выход без вопиющих операторов break. Требование для явного break было чем-то, что вышло из линии BCPL/B/C. Деннис Ритчи пишет (в ACM HOPL-II):

Например, конечный элемент, который выходит из оператора коммутатора BCPL, отсутствует на языке когда мы узнали об этом в 1960-х годах, и поэтому перегрузка ключевого слова break от оператора B и C, обязанность к расходящейся эволюции, а не к сознательному изменению.

Мне не удалось найти каких-либо исторических трудов о BCPL, но комментарий Ритчи предполагает, что break был более или менее исторической катастрофой. BCPL позже исправил проблему, но, возможно, Ритчи и Томпсон были слишком заняты изобретением Unix, чтобы беспокоиться о такой детали: -)

Ответ 10

Отсутствие автоматического прерывания, добавленного компилятором, позволяет использовать переключатель /case для проверки таких условий, как 1 <= a <= 3, удалив оператор break из 1 и 2.

switch(a) {
  case 1: //I'm between 1 and 3
  case 2: //I'm between 1 and 3
  case 3: //I'm between 1 and 3
          break;
}

Ответ 11

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

Ответ 12

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

например. используя HTTP-коды ответа для аутентификации пользователя с маркером времени

код ответа сервера 401 - токен устарел → регенерирует токен и регистрирует пользователя.
код ответа сервера 200 - токен в порядке → зарегистрировать пользователя.

в случае утверждений:

case 404:
case 500:
        {
            Log.v("Server responses","Unable to respond due to server error");
            break;
        }
        case 401:
        {
             //regenerate token
        }
        case 200:
        {
            // log in user
            break;
        }

Используя это, вам не нужно вызывать функцию входа в систему для ответа 401, потому что, когда токен регенерируется, среда выполнения переходит в регистр 200.

Ответ 13

Вы можете легко отделить другой тип числа, месяца, счета.
Это лучше, если в этом случае

public static void spanishNumbers(String span){

    span = span.toLowerCase().replace(" ", "");
    switch (span){
     case "1":    
     case "jan":  System.out.println("uno"); break;    
     case "2":      
     case "feb":  System.out.println("dos"); break;    
     case "3":     
     case "mar":  System.out.println("tres"); break;   
     case "4":   
     case "apr":  System.out.println("cuatro"); break;
     case "5":    
     case "may":  System.out.println("cinco"); break;
     case "6":     
     case "jun":  System.out.println("seis"); break;
     case "7":    
     case "jul":  System.out.println("seite"); break;
     case "8":    
     case "aug":  System.out.println("ocho"); break;
     case "9":   
     case "sep":  System.out.println("nueve"); break;
     case "10":    
     case "oct": System.out.println("diez"); break;
     }
 }

Ответ 14

Теперь я работаю над проектом, где мне нужно break в моей инструкции switch, иначе код не будет работать. Горе со мной, и я дам вам хороший пример того, почему вам нужно break в вашем заявлении switch.

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

В этом случае у вас есть:

  • State1. Подождите, пока пользователь не войдет в число.
  • Состояние2. Распечатайте сумму.
  • state3 - рассчитать сумму

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

Вот пример кода:

while(1){
    switch(state){
      case state1:
        // Wait for user input code
        state = state3; // Jump to state3
        break;
      case state2:
        //Print the sum code
        state = state3; // Jump to state3;
      case state3:
        // Calculate the sum code
        state = wait; // Jump to state1
        break;
    }
}

Если мы не используем break, он будет выполняться в этом порядке, state1, state2 и state3. Но используя break, мы избегаем этого сценария и можем упорядочить в правильной процедуре, которая должна начинаться с состояния1, а затем в состоянии 3 и, наконец, не в состоянии state2.

Ответ 15

Как говорили люди раньше, нужно разрешить провал, и это не ошибка, это особенность. Если слишком много операторов break раздражают вас, вы можете легко избавиться от них, используя вместо этого инструкции return. Это на самом деле хорошая практика, потому что ваши методы должны быть как можно меньше (для удобства чтения и ремонтопригодности), поэтому оператор switch уже достаточно велик для метода, следовательно, хороший метод не должен содержать ничего другого, это пример:

public class SwitchTester{
    private static final Log log = LogFactory.getLog(SwitchTester.class);
    public static void main(String[] args){
        log.info(monthsOfTheSeason(Season.WINTER));
        log.info(monthsOfTheSeason(Season.SPRING));
        log.info(monthsOfTheSeason(Season.SUMMER));
        log.info(monthsOfTheSeason(Season.AUTUMN));
    }

    enum Season{WINTER, SPRING, SUMMER, AUTUMN};

    static String monthsOfTheSeason(Season season){
        switch(season){
            case WINTER:
                return "Dec, Jan, Feb";
            case SPRING:
                return "Mar, Apr, May";
            case SUMMER:
                return "Jun, Jul, Aug";
            case AUTUMN:
                return "Sep, Oct, Nov";
            default:
                //actually a NullPointerException will be thrown before reaching this
                throw new IllegalArgumentException("Season must not be null");
        }        
    }
}   

Выполнение печатает:

12:37:25.760 [main] INFO lang.SwitchTester - Dec, Jan, Feb
12:37:25.762 [main] INFO lang.SwitchTester - Mar, Apr, May
12:37:25.762 [main] INFO lang.SwitchTester - Jun, Jul, Aug
12:37:25.762 [main] INFO lang.SwitchTester - Sep, Oct, Nov

как ожидалось.

Ответ 16

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