Відповіді:
Іноді корисно мати кілька випадків, пов’язаних з одним блоком коду, наприклад
case 'A':
case 'B':
case 'C':
doSomething();
break;
case 'D':
case 'E':
doSomethingElse();
break;
і т. д. Просто приклад.
На моєму досвіді, як правило, це поганий стиль "провалюватися" і виконувати кілька блоків коду для одного випадку, але в деяких ситуаціях це може бути використано.
// Intentional fallthrough.
коли упустите перерву. На мою думку, це не стільки поганий стиль, скільки "легко забути перерву". PS Звичайно, не в простих випадках, як у самій відповіді.
case
чином зібрано кілька s. Якщо між ними є код, то так, коментар, ймовірно, заслуговує.
case
, так: case 'A','B','C': doSomething(); case 'D','E': doSomethingElse();
без необхідності перерви між справами. Паскаль міг це зробити: "Оператор case порівнює значення порядкового виразу з кожним селектором, який може бути константою, піддіапазоном або їх списком, розділеним комами". ( wiki.freepascal.org/Case )
Історично склався так , що це тому , що case
по суті , визначає напрямок label
, також відоме як цільова точка у вигляді goto
виклику. Оператор перемикання та пов'язані з ним випадки справді просто представляють багатогалузеву гілку з декількома потенційними точками входу в потік коду.
З огляду на це, було відзначено майже нескінченну кількість разів, що break
майже завжди є поведінкою за замовчуванням, яку ви віддаєте перевагу наприкінці кожного випадку.
Java походить від C, і це синтаксис від C.
Бувають випадки, коли ви хочете, щоб декілька операторів справи мали лише один шлях виконання. Нижче наведено зразок, який покаже вам, скільки днів у місяці.
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);
}
}
Я думаю, що це помилка. Як мовна конструкція її так само легко мати, break
як і за замовчуванням, і натомість мати fallthrough
ключове слово. Більшість коду, який я написав і прочитав, має перерву після кожного випадку.
continue <case name>
що дозволяє чітко вказати, з якою справою продовжувати;
case
в межах поточного switch
, це просто стає goto
. ;-)
Ви можете робити всілякі цікаві речі із випадками пропускання корпусу.
Наприклад, скажімо, що ви хочете зробити певну дію для всіх випадків, але в певному випадку ви хочете зробити цю дію плюс щось інше. Використання оператора перемикання з пропусканням зробило б це досить просто.
switch (someValue)
{
case extendedActionValue:
// do extended action here, falls through to normal action
case normalActionValue:
case otherNormalActionValue:
// do normal action here
break;
}
Звичайно, легко забути break
твердження в кінці справи і спричинити несподівану поведінку. Хороші компілятори попереджатимуть вас, коли ви пропустите оператор break.
Чому компілятор автоматично не ставить оператори розриву після кожного блоку коду в комутаторі?
Залишаючи осторонь гарне бажання мати можливість використовувати ідентичний блок для кількох випадків (які можуть бути спеціально розроблені) ...
Це з історичних причин? Коли ви хочете виконати кілька блоків коду?
Це, головним чином, для сумісності з C, і, мабуть, давній хакер із старих часів, коли goto
ключові слова блукали по землі. Це , звичайно, дає змогу робити деякі дивовижні речі, наприклад , пристрій Даффа , але чи то це на його користь чи проти - це… аргументація в кращому випадку.
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
Тому вам не доведеться повторювати код, якщо вам потрібно кілька випадків, щоб зробити одне і те ж:
case THIS:
case THAT:
{
code;
break;
}
Або ви можете робити такі речі:
case THIS:
{
do this;
}
case THAT:
{
do that;
}
По-каскадному.
Дійсно схильність до помилок / плутанини, якщо ви запитаєте мене.
do this
і do that
для цього, але тільки do that
для цього?
Що стосується історичних записів, Тоні Хоаре вигадав випадок у 1960-х роках, під час революції "структурованого програмування". Заява про справу Тоні підтримує декілька міток на кожний випадок і автоматичний вихід без смердючих break
тверджень. Вимога до явного break
полягала в тому, що виходило з лінії BCPL / B / C. Денніс Річі пише (в ACM HOPL-II):
Наприклад, завершення, яке виходить з оператора переключення BCPL, не було в мові, коли ми дізналися його в 1960-х роках, і тому перевантаження ключового слова перерви для виходу з оператора вимикача B і C пов'язане з еволюційною еволюцією, а не усвідомленою змінити.
Мені не вдалося знайти жодних історичних творів про BCPL, але коментар Рітчі говорить про те, що це break
була більш-менш історична аварія. Пізніше BCPL вирішив проблему, але, можливо, Рітчі та Томпсон були надто зайняті винаходом Unix, щоб його непокоїти така деталь :-)
break
дозволяє "виконувати кілька блоків коду", і більше стосується мотивації цього вибору дизайну. Інші згадували про відому спадщину від С до Яви, і ця відповідь підштовхнула дослідження ще далі до днів до С. Я хотів би, щоб у нас був такий (хоча і дуже примітивний) шаблон, який відповідає з самого початку.
Java походить від мови C, спадщина якої включає техніку, відому як Пристрій Даффа . Це оптимізація, яка спирається на той факт, що контроль падає від одного випадку до іншого, за відсутності break;
заяви. До того моменту, коли С був стандартизований, коду такого типу "в природі" було багато, і змінити мову, щоб порушити такі конструкції, було б контрпродуктивно.
Як люди говорили раніше, це дозволити пропуск, і це не помилка, це особливість. Якщо занадто багато 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
як і очікувалося.
Відсутність автоматичного розриву, доданого компілятором, дозволяє використовувати перемикач / корпус для перевірки таких умов, як 1 <= a <= 3
видалення оператора розриву з 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;
}
Це старе питання, але насправді я сьогодні стикався з використанням справи без заяви про перерву. Не використовувати перерву насправді дуже корисно, коли вам потрібно поєднувати різні функції послідовно.
наприклад, використання кодів відповіді 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.
Ви можете легко відокремити інший тип числа, місяця, рахунку.
Це краще, якщо в цьому випадку;
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;
}
}
Зараз я працюю над проектом, де мені це потрібно break
в моєму операторі перемикача, інакше код не буде працювати. Потерпіть зі мною, і я дам вам хороший приклад того, чому вам це потрібно, break
у вашій заяві про перемикання.
Уявіть, у вас є три стани: один, який чекає, поки користувач введе число, другий для його обчислення і третій для друку суми.
У такому випадку у вас є:
Дивлячись на держави, ви хотіли б , щоб порядок поборів , щоб почати на 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 , состояніе2 і state3 . Але, використовуючи break
, ми уникаємо цього сценарію і можемо замовити в правильній процедурі, яка повинна починатися з state1, then state3 і останнього, але не менш важливого стану2.
break
.