Почему компилятор автоматически не помещает инструкции 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
Точно, потому что с некоторым умным размещением вы можете выполнять блоки в каскаде.