Використання оператора switch із діапазоном значень у кожному випадку?


92

У Java, чи можна написати оператор switch, коли кожен випадок містить більше одного значення? Наприклад (хоча очевидно, що наступний код не буде працювати):

switch (num) {
    case 1 .. 5:
        System.out.println("testing case 1 to 5");
        break;
    case 6 .. 10:
        System.out.println("testing case 6 to 10");
        break;
}

Я думаю, що це можна зробити в Objective C, чи є подібне у Java? Або я повинен просто використовувати if, else ifзаяву замість цього?


Існують навіть розширення в простому C, які дозволяють це зробити.
arshajii

У такому випадку, можливо, if/elseє кращим рішенням.
Ерік Ван,

Відповіді:


98

У Java немає нічого подібного. Чому б просто не зробити наступне?

public static boolean isBetween(int x, int lower, int upper) {
  return lower <= x && x <= upper;
}

if (isBetween(num, 1, 5)) {
  System.out.println("testing case 1 to 5");
} else if (isBetween(num, 6, 10)) {
  System.out.println("testing case 6 to 10");
}

1
Це чудово працює і просто. Крім того, якщо ви хочете вибрати цифри, що не в межах діапазону, все, що вам потрібно, це якщо (! IsBe Between ..., хороша робота.
a54studio

1
@missingfaktor Я трохи критикував вашу відповідь. Отже, ви, мабуть, захочете щось відповісти. +1, однак.
Олександр Малахов

@MCEmperor, будь ласка, не редагуйте мою відповідь за допомогою ваших особистих переваг форматування. Це не корисна редакція.
missingfaktor

@missingfaktor Вибачте. Але ця редакція була схвалена давно; Я навіть не пам’ятав, що коли-небудь це робив.
Імператор MC

76

Найближче до такої поведінки за допомогою switchвисловлювань є

switch (num) {
case 1:
case 2:
case 3:
case 4:
case 5:
     System.out.println("1 through 5");
     break;
case 6:
case 7:
case 8:
case 9:
case 10:
     System.out.println("6 through 10");
     break;
}

Використовуйте ifтвердження.


29

інша альтернатива - використання математичної операції шляхом її розділення, наприклад:

switch ((int) num/10) {
    case 1:
        System.out.println("10-19");
        break;
    case 2:
        System.out.println("20-29");
        break;
    case 3:
        System.out.println("30-39");
        break;
    case 4:
        System.out.println("40-49");
        break;
    default:
        break;
}

Але, як бачите, це можна використовувати лише тоді, коли в кожному випадку діапазон фіксований.


6
Це чудово працює з кодами стану http, розділеними на 100.
Стефан,

13

Я не думаю, що ви можете зробити це на Java. Найкраще - просто поставити код в останньому регістрі діапазону.

switch (num) {
  case 1: case 2: case 3: case 4: case 5: 
     System.Out.Println("testing case 1 to 5");
     break;
  case 6: case 7: case 8: case 9: case 10:
     System.Out.Println("testing case 6 to 10");
     break;
  default:
     //
}

10
  case 1: case 2: case 3: case 4: case 5: 
         System.out.println("testing case 1 to 5");
         break;
  case 6: case 7: case 8: case 9: case 10:
         System.out.println("testing case 6 to 10");
         break;
  default:
         System.out.println("default"); 

9

Я знаю, що ця публікація стара, але я вважаю, що ця відповідь заслуговує на визнання. Немає необхідності уникати оператора перемикання. Це можна зробити в Java, але за допомогою оператора switch, а не у випадках. Він передбачає використання тернарних операторів.

public class Solution {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int num = Integer.parseInt(sc.nextLine());

        switch ((1 <= num && num <= 5 ) ? 0 :
                (6 <= num && num <= 10) ? 1 : 2) {

            case 0:
                System.out.println("I'm between one and five inclusive.");
                break;
            case 1:
                System.out.println("I'm between 6 and 10 inclusive.");
                break;
            case 2:
                System.out.println("I'm not between one and five or 6 and 10 inclusive.");
                break;
        }
    }
}

1
Приємне рішення! За допомогою Java 7 та новішої версії ви також можете увімкнути String, щоб ваші справи ще більше самодокументувались, наприклад, switch ((1 <= num && num <= 5 ) ? "1 .. 5" : ...а потім case "1 .. 5":.
Даніель Віддіс

@DanielWiddis: Я б запропонував використовувати enum замість рядків, щоб забезпечити узгодженість.
nmatt

@nmatt Загалом погоджуюсь. Я намагався дозволити використання синтаксису стилю "1 .. 5".
Даніель Віддіс

2
@DanielWiddis: Звичайно, це добре; Я б назвав константи переліку щось на зразок FROM_1_TO_5. Зазвичай діапазони мають певне значення, і в цьому випадку константи переліку можна назвати відповідно до значення діапазону.
nmatt

1
Я думаю, що ми можемо домовитись, що будь-який варіант кращий, ніж 0, 1 або 2.
Даніель Віддіс,

6

Або ви можете використовувати свої сольні кейси за призначенням і використати кейс за замовчуванням, щоб вказати інструкції щодо діапазону як:

switch(n) {
    case 1 : System.out.println("case 1"); break;
    case 4 : System.out.println("case 4"); break;
    case 99 : System.out.println("case 99"); break;
    default :
        if (n >= 10 && n <= 15)
            System.out.println("10-15 range"); 
        else if (n >= 100 && n <= 200)
            System.out.println("100-200 range");
        else
            System.out.println("Your default case");
        break;   
}

Це те, що я завжди роблю, але також додаю коментар між випадками, наприклад: // 10 - 15 див. Нижче за замовчуванням
Perdi Estaquel

5

Спробуйте це, якщо вам потрібно використовувати перемикач.

public static int range(int num){ 
    if ( 10 < num && num < 20)
        return 1;
    if ( 20 <= num && num < 30)
        return 2;
    return 3;
}

public static final int TEN_TWENTY = 1;
public static final int TWENTY_THIRTY = 2;

public static void main(String[]args){
    int a = 110;
    switch (range(a)){
        case TEN_TWENTY: 
            System.out.println("10-20"); 
            break;
        case TWENTY_THIRTY: 
            System.out.println("20-30"); 
            break;
        default: break;
    }
}

Ви можете дати пояснення теж?
user1140237

Діапазон функцій повертає деяке значення відповідно до вхідного аргументу, тому тут може бути зроблено виявлення "діапазону значень" разом із реченням регістру перемикача.
zl9394,

Це працює для мого випадку використання, у мене є 2 змінних int, і я хочу перевірити, чи є дві змінні в тому ж діапазоні, як (10-20), (20-30), .... ось так
Sameer Kazi

Я б запропонував використовувати enum замість магічних значень int.
nmatt

4

Ні, ви цього не можете зробити. Найкраще, що ви можете зробити - це

case 1:
case 2:
case 3:
case 4:
case 5: 
  System.Out.Println("testing case 1 to 5");
break;

3

Можна згрупувати кілька умов в одному і тому ж caseоператорі, використовуючи механізм проходження через дозволені оператори switch, це згадується в підручнику Java і повністю зазначено в розділі §14.11. Заява про перемикання специфікації мови Java .

Наступний фрагмент коду взятий із прикладу в підручнику, він обчислює кількість днів у кожному місяці (нумерується з 1 по 12 місяць):

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;
}

Як бачите, для охоплення діапазону значень в одному caseтвердженні єдиною альтернативою є перерахування кожного з можливих значень окремо, одне за іншим. Як додатковий приклад, ось як реалізувати псевдокод у питанні:

switch(num) {
    case 1: case 2: case 3: case 4: case 5:
        System.out.println("testing case 1 to 5");
        break;
    case 6: case 7: case 8: case 9: case 10:
        System.out.println("testing case 6 to 10");
        break;
}

3

Ви можете використовувати a enumдля представлення діапазонів,

public static enum IntRange {
  ONE_TO_FIVE, SIX_TO_TEN;
  public boolean isInRange(int v) {
    switch (this) {
    case ONE_TO_FIVE:
      return (v >= 1 && v <= 5);
    case SIX_TO_TEN:
      return (v >= 6 && v <= 10);
    }
    return false;
  }

  public static IntRange getValue(int v) {
    if (v >= 1 && v <= 5) {
      return ONE_TO_FIVE;
    } else if (v >= 6 && v <= 10) {
      return SIX_TO_TEN;
    }
    return null;
  }
}

3

Він підтримується на Java 12. Перевірте JEP 354 . Тут відсутні можливості "діапазону", але вони можуть бути корисними.

switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);//number of letters
    case TUESDAY                -> System.out.println(7);
    case THURSDAY, SATURDAY     -> System.out.println(8);
    case WEDNESDAY              -> System.out.println(9);
}

Ви також зможете реалізувати це на ints. Зауважте, що ваш оператор switch повинен бути вичерпним (з використанням defaultключового слова або використання всіх можливих значень у випадках).


3

Ось прекрасний і мінімалістичний спосіб

(num > 1 && num < 5) ? first_case_method() 
                     : System.out.println("testing case 1 to 5")
                     : (num > 5 && num < 7)  ? System.out.println("testing case 5 to 7") 
                     : (num > 7 && num < 8)  ? System.out.println("testing case 7 to 8") 
                     : (num > 8 && num < 9)  ? System.out.println("testing case 8 to 9") 
                     : ... 
                     : System.out.println("default");

Ви можете пояснити це ?? - Я дійсно отримую "міні-ifs", але крім цього idk.
Камін Паллагі,

@Tunaki це if..elseifальтернатива використання каскадного потрійного оператора ( condition ? statementIfTrue : statementIfFalse).
Віллієм,

2

Відповідь @missingfaktor справді правильна, але дещо надто складна. Код є більш багатослівним (принаймні для безперервних інтервалів), ніж він міг би бути, і вимагає перевантажень / закидів та / або параметризації для long, float, Integer тощо

if (num < 1)
    System.Out.Println("invalid case: " + num); // you should verify that anyway
else if (num <= 5)
    System.Out.Println("1 to 5");
else if (num <= 10)
    System.Out.Println("6 to 10");
else if (num <= 42)
    System.Out.Println("11 to 42");
else    
    System.Out.Println("43 to +infinity");

3
Вибачте за пізню відповідь, останнім часом я не можу встигати за відповідями SO. Я відповім на вашу критику по одному. 1. Код трохи детальніший, так, і він також виконує надлишкові обчислення. Але це IMO сприяє ясності в цій справі. У вашому коді потрібно пам’ятати попередні випадки, коли хтось провалюється по сходах.
missingfaktor

2
Що стосується вимог до перевантажень та зліпок, це не є вагомою критикою ІМО. Те, що Java не має розумного способу абстрагування над числовими типами, говорить більше про обмеження Java, ніж про цей підхід. Можливо, ви захочете вивчити Numтип класу Хаскелла, якщо хочете краще зрозуміти цей момент.
missingfaktor

@missingfaktor 1. Я думаю, це справа смаку. Маючи справу з безперервними інтервалами, мені особисто подобається думати про ifs, ніби я поступово виливаю нижній піддіапазон. Крім того, надлишкові обчислення не проблема взагалі, але зайве порівняння трохи турбує: він стає простіше зробити примикають порівняння з синхронізації, наприклад , після деякого редагування: if (isBetween(x, 1, 4)) {...} else if (isBetween(x, 6, 10)). У всякому разі, не велика справа.
Олександр Малахов

2. Погоджено - обмеження Java, але саме з цим нам доведеться працювати, і ваш оригінальний код буде продубльовано для різних типів. У цьому конкретному випадку проблему можна пом'якшити за допомогою класу Number , хоча підхід Haskell є кращим (ніколи не дізнався Haskell, але він нагадує "Concepts Light" на C ++. Крім того, я вважаю, що ви мали на увазі Real, ні Num).
Олександр Малахов

2

Використовуйте NavigableMapреалізацію, наприклад TreeMap.

/* Setup */
NavigableMap<Integer, Optional<String>> messages = new TreeMap<>();
messages.put(Integer.MIN_VALUE, Optional.empty());
messages.put(1, Optional.of("testing case 1 to 5"));
messages.put(6, Optional.of("testing case 6 to 10"));
messages.put(11, Optional.empty());

/* Use */
messages.floorEntry(3).getValue().ifPresent(System.out::println);

Відмінне рішення! не забудьте перевірити наявність нуля, if (messages.floorEntry(value)!=null) якщо ви використовуєте ціле значення
Ch Vas

1
@ChVas Те, як тут встановлено карту, floorEntry()ніколи не повернеться null(введення Integer.MIN_VALUEключа призначене для запобігання цьому). Але, незалежно від типу вашого значення, вам потрібно вирішити, як обробляти ключі поза допустимим діапазоном.
erickson

0

Для вхідного номера в діапазоні 0..100

int n1 = 75; // input value
String res; int n=0; 
int[] a ={0,20,35,55,70,85,101};

for(; n1>=a[n]; n++);
switch(6-n+1) {
  case 1: res="A"; break;
  case 2: res="B"; break;
  case 3: res="C"; break;
  case 4: res="D"; break;
  case 5: res="E"; break;
  default:res="F";
}
System.out.println(res);

0

Цей тип поведінки не підтримується в Java. Однак якщо у вас є великий проект, якому це потрібно, розгляньте можливість змішування коду Groovy у своєму проекті. Код Groovy компілюється в байтовий код і може запускатися за допомогою JVM. Компанія, в якій я працюю, використовує Groovy для написання сервісних класів, а Java - для написання всього іншого.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.