Menggunakan pernyataan switch dengan rentang nilai dalam setiap kasus?

94

Di Java, apakah mungkin untuk menulis pernyataan switch di mana setiap case berisi lebih dari satu nilai? Misalnya (meskipun jelas kode berikut tidak akan berfungsi):

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

Saya rasa ini bisa dilakukan di Objective C, apakah ada hal serupa di Java? Atau haruskah saya menggunakan if, else ifpernyataan saja?

davidx1
sumber
Bahkan ada ekstensi dalam C biasa yang memungkinkan untuk ini.
arshajii
Dalam hal ini, mungkin if/elsemerupakan solusi yang lebih baik.
Eric Wang

Jawaban:

100

Java tidak memiliki hal semacam itu. Mengapa tidak melakukan yang berikut ini saja?

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");
}
missingfaktor
sumber
1
Ini bekerja dengan baik dan sederhana. Juga jika Anda ingin memilih nomor yang tidak dalam kisaran yang Anda butuhkan adalah jika (! IsBetween ..., kerja bagus.
a54studio
1
@missingfaktor Saya mengkritik jawaban Anda sedikit. Jadi, Anda mungkin ingin membalas sesuatu. +1 sekalipun.
Alexander Malakhov
@MCEmperor, tolong jangan edit jawaban saya dengan preferensi format pribadi Anda. Itu bukan hasil edit yang berguna.
missingfaktor
Maaf. Tapi suntingan itu sudah lama disetujui; Saya bahkan tidak ingat saya pernah melakukan itu.
Kaisar MC
78

Yang paling dekat dengan perilaku semacam itu dengan switchpernyataan adalah

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

Gunakan ifpernyataan.

Jeffrey
sumber
30

Alternatif lain adalah menggunakan operasi matematika dengan membaginya, misalnya:

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

Tapi, seperti yang Anda lihat, ini hanya dapat digunakan ketika kisaran ditetapkan dalam setiap kasus.

Hayi Nukman
sumber
6
Ini berfungsi dengan baik dengan kode status http dibagi 100.
Stefan
14

Saya tidak berpikir Anda bisa melakukan itu di Jawa. Taruhan terbaik adalah dengan meletakkan kode di kasus terakhir kisaran.

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:
     //
}
blitzen
sumber
11

Saya tahu posting ini sudah tua tapi saya yakin jawaban ini layak mendapat pengakuan. Tidak perlu menghindari pernyataan sakelar. Ini dapat dilakukan di java tetapi melalui pernyataan switch, bukan kasusnya. Ini melibatkan penggunaan operator terner.

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;
        }
    }
}
DarkHark
sumber
1
Solusi bagus! Dengan Java 7 dan yang lebih tinggi Anda juga bisa mengaktifkan String sehingga kasus Anda lebih terdokumentasi sendiri, misalnya, switch ((1 <= num && num <= 5 ) ? "1 .. 5" : ...dan kemudian case "1 .. 5":.
Daniel Widdis
@DanielWiddis: Saya akan menyarankan menggunakan enum, bukan string, untuk memastikan konsistensi.
nmatt
@nmatt Umumnya setuju. Saya mencoba untuk mengizinkan penggunaan sintaks gaya "1 .. 5".
Daniel Widdis
2
@DanielWiddis: Tentunya hal yang baik; Saya akan memberi nama konstanta enum seperti FROM_1_TO_5. Biasanya range memiliki arti tertentu, dan dalam hal ini konstanta enum dapat diberi nama sesuai dengan arti range tersebut.
nmatt
1
Saya pikir kita bisa setuju opsi mana yang lebih baik dari 0, 1, atau 2.
Daniel Widdis
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"); 
Jitendra
sumber
6

Atau Anda dapat menggunakan kasing solo Anda sebagaimana dimaksud dan menggunakan kasing default Anda untuk menentukan instruksi jangkauan sebagai:

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;   
}
Oyzuu
sumber
Ini yang selalu saya lakukan, tetapi juga menambahkan komentar di antara kasus-kasus, misalnya: // 10 - 15 lihat di bawah default
Perdi Estaquel
5

Coba ini jika Anda harus menggunakan sakelar.

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;
    }
}
zl9394
sumber
bisakah anda memberikan penjelasan juga ..?
pengguna1140237
Rentang fungsi mengembalikan beberapa nilai sesuai dengan argumen input, sehingga deteksi "rentang nilai" dapat dilakukan di sini, digabungkan dengan klausa kasus sakelar.
zl9394
Ini berfungsi untuk kasus penggunaan saya, saya memiliki 2 variabel int dan saya ingin memeriksa apakah 2 variabel berada dalam kisaran yang sama seperti (10-20), (20-30), .... seperti ini
Sameer Kazi
Saya akan menyarankan menggunakan enum daripada nilai int sihir.
nmatt
4

Tidak, Anda tidak bisa melakukan itu. Hal terbaik yang dapat Anda lakukan adalah itu

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

Inilah cara yang indah dan minimalis untuk pergi

(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");
Williem
sumber
Bisakah Anda menjelaskan ini ?? - Saya mendapatkan 'mini ifs' tapi selain idk itu.
Kamin Pallaghy
@Tunaki ini adalah if..elseifalternatif yang digunakan dalam kaskade operator terner ( condition ? statementIfTrue : statementIfFalse).
Williem
3

Anda dapat mengelompokkan beberapa kondisi dalam casepernyataan yang sama menggunakan mekanisme fall through yang diizinkan oleh pernyataan switch, hal ini disebutkan dalam tutorial Java dan ditentukan sepenuhnya di bagian §14.11. Pernyataan switch dari Spesifikasi Bahasa Java .

Cuplikan kode berikut diambil dari contoh di tutorial, ini menghitung jumlah hari di setiap bulan (dinomori dari bulan 1 hingga bulan 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;
}

Seperti yang Anda lihat, untuk mencakup rentang nilai dalam satu casepernyataan, satu-satunya alternatif adalah mencantumkan setiap nilai yang mungkin secara individual, satu demi satu. Sebagai contoh tambahan, berikut ini cara mengimplementasikan pseudocode dalam pertanyaan:

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;
}
Óscar López
sumber
3

Anda bisa menggunakan an enumuntuk mewakili rentang Anda,

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;
  }
}
Elliott Frisch
sumber
3

Ini didukung pada Java 12. Lihat JEP 354 . Tidak ada kemungkinan "jangkauan" di sini, tetapi bisa berguna juga.

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

Anda harus bisa mengimplementasikannya di int juga. Perhatikan bahwa pernyataan switch Anda harus lengkap (menggunakan defaultkata kunci, atau menggunakan semua nilai yang mungkin dalam pernyataan kasus).

A_Arnold
sumber
2

Jawaban @missingfaktor memang benar tapi agak ribet. Kode lebih bertele-tele (setidaknya untuk interval kontinu) daripada bisa, dan membutuhkan overloads / casts dan / atau parameterization untuk long, float, integer dll

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");
Alexander Malakhov
sumber
3
Maaf atas tanggapan yang terlambat, saya tidak dapat mengikuti tanggapan SO belakangan ini. Saya akan membalas kritik Anda satu per satu. 1. Kode sedikit lebih bertele-tele, ya, dan juga melakukan beberapa komputasi yang berlebihan. Tapi IMO itu membantu kejelasan dalam kasus ini. Dalam kode Anda, orang harus mengingat kasus sebelumnya saat seseorang jatuh melalui tangga.
missingfaktor
2
Adapun membutuhkan kelebihan dan pemeran, itu bukan kritik yang valid IMO. Bahwa Java tidak memiliki cara yang masuk akal untuk mengabstraksi tipe numerik menunjukkan tentang keterbatasan Java, lebih dari tentang pendekatan ini. Anda mungkin ingin menjelajahi Numkelas-tipe Haskell jika Anda ingin memahami poin ini dengan lebih baik.
missingfaktor
@missingfaktor 1. Saya rasa itu masalah selera. Ketika berhadapan dengan interval kontinu, saya pribadi suka memikirkan ifs seolah-olah saya secara bertahap menumpahkan subrange yang lebih rendah. Selanjutnya, perhitungan berlebihan bukan masalah sama sekali, tapi perbandingan berlebihan agak mengkhawatirkan: mendapat sederhana untuk membuat perbandingan yang berdekatan tidak sinkron, misalnya setelah beberapa edit: if (isBetween(x, 1, 4)) {...} else if (isBetween(x, 6, 10)). Bagaimanapun, bukan masalah besar.
Alexander Malakhov
2. Setuju - Batasan Java, tapi itulah yang harus kami kerjakan dan kode asli Anda akan digandakan untuk berbagai jenis. Dalam kasus khusus ini, masalah dapat dikurangi dengan menggunakan kelas Number , meskipun pendekatan Haskell lebih baik (tidak pernah benar-benar mempelajari Haskell, tetapi ia menyerupai "Konsep Cahaya" dari C ++. Juga, saya yakin maksud Anda Real, bukan Num).
Alexander Malakhov
2

Gunakan NavigableMapimplementasi, seperti 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);
erickson
sumber
Solusi luar biasa! jangan lupa untuk memeriksa null menggunakan if (messages.floorEntry(value)!=null) jika Anda menggunakan nilai Integer
Ch Vas
1
@ChVas Cara pengaturan peta di sini, floorEntry()tidak akan pernah kembali null(memasukkan Integer.MIN_VALUEkunci dimaksudkan untuk mencegahnya). Namun, apa pun jenis nilainya, Anda perlu memutuskan cara menangani kunci di luar rentang yang valid.
erickson
0

Untuk nomor masukan dalam rentang 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);
zemiak
sumber
0

Jenis perilaku ini tidak didukung di Java. Namun, jika Anda memiliki proyek besar yang membutuhkan ini, pertimbangkan untuk menggabungkan kode Groovy dalam proyek Anda. Kode Groovy dikompilasi menjadi kode byte dan dapat dijalankan dengan JVM. Perusahaan tempat saya bekerja menggunakan Groovy untuk menulis kelas layanan dan Java untuk menulis yang lainnya.

isoplayer
sumber