Зачем нам нужен перерыв после падежа? - PullRequest
90 голосов
/ 26 апреля 2010

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

Ответы [ 17 ]

91 голосов
/ 26 апреля 2010

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

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

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

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

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

29 голосов
/ 26 апреля 2010

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

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

27 голосов
/ 26 апреля 2010

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);
    }
}
13 голосов
/ 26 апреля 2010

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

13 голосов
/ 26 апреля 2010

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

Например, допустим, вы хотите выполнить определенное действие для всех случаев, но в определенном случае вы хотите выполнить это действие плюс что-то еще. Использование оператора 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.

6 голосов
/ 26 апреля 2010

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

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

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

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

4 голосов
/ 26 апреля 2010

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

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

Или вы можете сделать что-то вроде:

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

В каскадеfashion.

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

3 голосов
/ 26 апреля 2010

Java происходит от C, чье наследие включает технику, известную как Устройство Даффа . Это оптимизация, основанная на том факте, что управление переходит от одного случая к другому, в отсутствие оператора break;. К тому времени, когда C был стандартизирован, было много кода, подобного этому «в дикой природе», и было бы контрпродуктивно менять язык, чтобы ломать такие конструкции.

3 голосов
/ 08 сентября 2018

break после переключателя case s используется, чтобы избежать падения в выражениях переключателя. Хотя интересно, что теперь это может быть достигнуто с помощью вновь сформированных меток переключателей, реализованных с помощью JEP-325 .

С этими изменениями можно избежать break с каждым переключателем case, как показано далее: -

public class SwitchExpressionsNoFallThrough {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int value = scanner.nextInt();
        /*
         * Before JEP-325
         */
        switch (value) {
            case 1:
                System.out.println("one");
            case 2:
                System.out.println("two");
            default:
                System.out.println("many");
        }

        /*
         * After JEP-325
         */
        switch (value) {
            case 1 ->System.out.println("one");
            case 2 ->System.out.println("two");
            default ->System.out.println("many");
        }
    }
}

При , выполняющем вышеуказанный код с JDK-12 , сравнительный вывод можно рассматривать как

//input
1
// output from the implementation before JEP-325
one
two
many
// output from the implementation after JEP-325
one

и

//input
2
// output from the implementation before JEP-325
two
many
// output from the implementation after JEP-325
two

и, конечно, вещь без изменений

// input
3
many // default case match
many // branches to 'default' as well
3 голосов
/ 26 апреля 2010

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

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

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

...