Когда уместно использовать сквозной (классический) оператор switch? Рекомендуется и поощряется ли такое использование или его следует избегать любой ценой?
Когда уместно использовать сквозной (классический) оператор switch? Рекомендуется и поощряется ли такое использование или его следует избегать любой ценой?
Ответы:
Вот пример, где это было бы полезно.
public Collection<LogItems> GetAllLogItems(Level level) {
Collection<LogItems> result = new Collection<LogItems>();
switch (level) {
// Note: fall through here is INTENTIONAL
case All:
case Info:
result.Add(GetItemsForLevel(Info));
case Warning:
result.Add(GetItemsForLevel(Warning));
case Error:
result.Add(GetItemsForLevel(Error));
case Critical:
result.Add(GetItemsForLevel(Critical));
case None:
}
return result;
}
Я думаю, что такого рода вещи (где один случай включает другой) довольно редки, поэтому некоторые новые языки либо не допускают фолловера, либо требуют специального синтаксиса для этого.
// INTENTIONAL FALL THROUGH HERE
комментария с заглавными буквами.
GetItemsForLevel(Info)
вызов GetItemsForLevel(Warning)
и так далее.
Я использую их, когда определенные функции должны применяться для более чем одного значения. Например, допустим, у вас есть объект со свойством с именем operationCode. Если код равен 1, 2, 3 или 4, вы хотите запуститьOperationX (). Если это 5 или 6, вы хотите запуститьOperationY () и 7 вы запускаете OperationZ (). Зачем иметь 7 полных случаев с функциональностью и пробелами, когда вы можете использовать провалы?
Я думаю, что это вполне допустимо в определенных ситуациях, особенно если оно избегает 100 операторов if-else. знак равно
switch
несколько case
объектов, привязанных к одному и тому же коду. Это отличается от провала, когда выполнение одного case
продолжается в следующем из-за отсутствия break
между ними.
Проходные случаи прекрасно. Я часто нахожу, что перечисление используется во многих местах, и что, когда вам не нужно различать некоторые случаи, легче использовать сквозную логику.
Например (обратите внимание на пояснительные комментарии):
public boolean isAvailable(Server server, HealthStatus health) {
switch(health) {
// Equivalent positive cases
case HEALTHY:
case UNDER_LOAD:
return true;
// Equivalent negative cases
case FAULT_REPORTED:
case UNKNOWN:
case CANNOT_COMMUNICATE:
return false;
// Unknown enumeration!
default:
LOG.warn("Unknown enumeration " + health);
return false;
}
}
Я считаю этот вид использования вполне приемлемым.
case X: case Y: doSomething()
и есть большая разница case X: doSomething(); case Y: doAnotherThing()
. В первом случае намерение является довольно явным, а во втором - провал может быть намеренным или нет. По моему опыту, первый пример никогда не вызывает никаких предупреждений в компиляторах / анализаторах кода, в то время как второй делает. Лично я бы назвал второй пример «провалившимся», хотя и не уверен насчет «официального» определения.
Это зависит от:
Две основные проблемы, связанные с переходом одного дела на другое:
Это делает ваш код зависимым от порядка операторов case. Это не тот случай, если вы никогда не провалитесь, и это добавляет некоторую сложность, которая часто нежелательна.
Не очевидно, что код для одного случая включает в себя код для одного или нескольких последующих случаев.
Некоторые места явно запрещают проваливаться. Если вы не работаете в таком месте, и если вы чувствуете себя комфортно с практикой, и если нарушение кода, о котором идет речь, не принесет никаких реальных страданий, то это может быть не самым худшим в мире. Если вы делаете это, тем не менее, не забудьте разместить привлекающий внимание комментарий, чтобы предупредить тех, кто придет позже (включая будущее вас).
Вот быстрый (по общему признанию, неполный (без специальной обработки високосного года)) пример провала, делающего мою жизнь проще:
function get_julian_day (date) {
int utc_date = date.getUTCDate();
int utc_month = date.getUTCMonth();
int julian_day = 0;
switch (utc_month) {
case 11: julian_day += 30;
case 10: julian_day += 31;
case 9: julian_day += 30;
case 8: julian_day += 31;
case 7: julian_day += 31;
case 6: julian_day += 30;
case 5: julian_day += 31;
case 4: julian_day += 30;
case 3: julian_day += 31;
case 2: julian_day += 28;
case 1: julian_day += 31;
default: break;
}
return julian_day + utc_date;
}
Если я чувствую необходимость перейти от одного случая к другому (редко, по общему признанию), я предпочитаю быть очень явным и goto case
, конечно, это предполагает, что ваш язык поддерживает это.
Поскольку падение происходит так редко, и его очень легко не заметить при чтении кода, я чувствую, что уместно быть явным - и переход, даже если это так, должен выделяться, как больной большой палец.
Это также помогает избежать ошибок, которые могут возникнуть при изменении порядка дел.