Почему компилятор автоматически не помещает операторы завершения после каждого блока кода в переключателе? Это по историческим причинам? Когда Вы хотели бы, чтобы несколько блоков кода выполнились?
Иногда полезно иметь несколько вариантов, связанных с одним и тем же блоком кода, например
case 'A':
case 'B':
case 'C':
doSomething();
break;
case 'D':
case 'E':
doSomethingElse();
break;
и т. Д. Просто пример.
По моему опыту, обычно плохой стиль - «проваливаться» и выполнять несколько блоков кода для одного случая, но в некоторых ситуациях это может быть использовано.
Таким образом, вам не нужно повторять код, если вам нужно несколько случаев, чтобы сделать то же самое вещь:
case THIS:
case THAT:
{
code;
break;
}
Или вы можете сделать что-то вроде:
case THIS:
{
do this;
}
case THAT:
{
do that;
}
Каскадным способом.
На самом деле подвержены ошибкам / путанице, если вы спросите меня.
Исторически это потому, что случай
по существу определял метка
, также известная как целевая точка вызова goto
. Оператор switch и связанные с ним случаи на самом деле просто представляют собой многостороннюю ветвь с несколькими потенциальными точками входа в поток кода.
Все это было замечено почти бесконечное количество раз, что break
почти всегда является поведением по умолчанию, которое вы бы предпочли иметь в конце каждого случая.
Я думаю, что это ошибка. В качестве языковой конструкции так же легко иметь break
по умолчанию и вместо этого использовать ключевое слово fallthrough
. Большая часть кода, который я написал и прочитал, имеет перерыв после каждого случая.
Почему компилятор не помещает автоматически операторы break после каждого блока кода в переключателе?
Оставляя в стороне хорошее желание чтобы иметь возможность использовать один и тот же блок в нескольких случаях (которые могут быть особенными) ...
Это по историческим причинам? Когда вы хотите, чтобы выполнялось несколько блоков кода?
Это в основном для совместимости с C, и, возможно, это древний прием с тех времен, когда ключевые слова goto
бродили по земле. Он действительно , конечно же, позволяет использовать некоторые удивительные вещи, такие как Устройство Даффа , но то, за или против, это аргумент… в лучшем случае.
Java является производным от C, наследие которого включает метод, известный как Устройство Даффа .
Это оптимизация, основанная на том факте, что контроль переходит от одного случая к другому, в отсутствие разрыва ;
оператора. К тому времени, когда C был стандартизирован, такого кода «в дикой природе» было достаточно, и было бы контрпродуктивно менять язык, чтобы разрушить такие конструкции.
Java происходит от C, а это синтаксис от C.
Бывают случаи, когда вы хотите, чтобы несколько операторов case имели только один путь выполнения. { {1}} Ниже приведен образец, который покажет вам, сколько дней в месяце.
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);
}
}
, потому что бывают ситуации, когда вы хотите пройти через первый блок, например, чтобы избежать написания одного и того же кода в нескольких блоках, но все же иметь возможность разделить их для большего контроля. Есть и масса других причин.
Что касается исторических данных, Тони Хоар изобрел оператор case в 1960-х, во время революции «структурного программирования». Оператор case Тони поддерживает несколько меток для каждого case и автоматический выход без отвратительных операторов break
. Требование явного разрыва
исходило из линии BCPL / B / C. Деннис Ритчи пишет (в ACM HOPL-II):
Например, конечный регистр, который ускользает из оператора включения BCPL, отсутствовал в языке , когда мы его изучили в 1960-х годах, и поэтому перегрузка ключевое слово break для выхода из операторов switch B и C обязано дивергентной эволюции, а не сознательным изменениям.
Мне не удалось найти никаких исторических работ о BCPL, но комментарий Ричи предполагает, что разрыв
был более или менее исторической случайностью. Позднее BCPL исправил проблему, но, возможно, Ричи и Томпсон были слишком заняты изобретением Unix, чтобы беспокоиться о таких деталях: -)
Отсутствие автоматического прерывания, добавляемого компилятором, позволяет использовать переключатель / регистр для проверки таких условий, как 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;
}
Именно потому, что при некотором умном размещении вы можете выполнять блоки каскадом.
С провалом футляра можно делать разные интересные вещи.
Например, допустим, вы хотите выполнить определенное действие для всех случаев, но в определенном случае вы хотите выполнить это действие и что-то еще. Использование оператора 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.