Sử dụng câu lệnh switch với phạm vi giá trị trong từng trường hợp?


92

Trong Java, có thể viết một câu lệnh switch trong đó mỗi trường hợp chứa nhiều hơn một giá trị không? Ví dụ: (mặc dù rõ ràng mã sau sẽ không hoạt động):

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

Tôi nghĩ điều này có thể được thực hiện trong Objective C, có điều tương tự trong Java không? Hay tôi chỉ nên sử dụng if, else ifcâu lệnh thay thế?


Thậm chí có các phần mở rộng bằng C đơn giản cho phép điều này.
arshajii

Trong trường hợp đó, có lẽ if/elselà một giải pháp tốt hơn.
Eric Wang

Câu trả lời:


98

Java không có gì loại đó. Tại sao không chỉ làm những điều sau?

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
Điều này hoạt động tuyệt vời và đơn giản. Ngoài ra, nếu bạn muốn chọn các số không nằm trong phạm vi, tất cả những gì bạn cần là if (! IsBetween ..., làm tốt lắm.
a54studio

1
@missingfaktor Tôi đã chỉ trích câu trả lời của bạn một chút. Vì vậy, bạn có thể muốn trả lời một cái gì đó. +1 mặc dù.
Alexander Malakhov

@MCEmpaster, vui lòng không chỉnh sửa câu trả lời của tôi với tùy chọn định dạng cá nhân của bạn. Đó không phải là một chỉnh sửa hữu ích.
missfaktor

@missingfaktor Xin lỗi. Nhưng bản chỉnh sửa đó đã được phê duyệt từ lâu; Tôi thậm chí còn không nhớ mình đã từng làm điều đó.
MC Emperor

76

Cách gần nhất bạn có thể đạt được loại hành vi đó với các switchcâu lệnh là

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

Sử dụng các ifcâu lệnh.


29

phương pháp thay thế khác là sử dụng phép toán bằng cách chia nó, ví dụ:

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

Tuy nhiên, như bạn có thể thấy, điều này chỉ có thể được sử dụng khi phạm vi được cố định trong mỗi trường hợp.


6
Điều này hoạt động tốt với mã trạng thái http chia cho 100.
Stefan

13

Tôi không nghĩ rằng bạn có thể làm điều đó trong Java. Đặt cược tốt nhất là chỉ đặt mã trong trường hợp cuối cùng của phạm vi.

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

Tôi biết bài đăng này đã cũ nhưng tôi tin rằng câu trả lời này xứng đáng được ghi nhận. Không cần phải tránh câu lệnh switch. Điều này có thể được thực hiện trong java nhưng thông qua câu lệnh switch, không phải trường hợp. Nó liên quan đến việc sử dụng các toán tử bậc ba.

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
Giải pháp tốt! Với Java 7 trở lên, bạn cũng có thể bật một Chuỗi để các trường hợp của bạn thậm chí còn tự lập tài liệu hơn, ví dụ: switch ((1 <= num && num <= 5 ) ? "1 .. 5" : ...và sau đó case "1 .. 5":.
Daniel Widdis

@DanielWiddis: Tôi khuyên bạn nên sử dụng enum thay vì chuỗi, để đảm bảo tính nhất quán.
nmatt

@nmatt Nói chung là đồng ý. Tôi đang cố gắng cho phép sử dụng cú pháp kiểu "1 .. 5".
Daniel Widdis

2
@DanielWiddis: Chắc chắn là một điều tốt; Tôi sẽ đặt tên cho các hằng số enum giống như FROM_1_TO_5. Thông thường các phạm vi có một ý nghĩa nhất định, và trong trường hợp đó, các hằng số enum có thể được đặt tên theo ý nghĩa của phạm vi.
nmatt

1
Tôi nghĩ chúng ta có thể đồng ý một trong hai lựa chọn tốt hơn là 0, 1 hoặc 2.
Daniel Widdis

6

Hoặc bạn có thể sử dụng các trường hợp solo của mình như dự định và sử dụng trường hợp mặc định của bạn để chỉ định các hướng dẫn phạm vi như:

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

Đây là những gì tôi luôn làm, nhưng cũng thêm nhận xét giữa các trường hợp, ví dụ: // 10 - 15 xem bên dưới mặc định
Perdi Estaquel

5

Hãy thử điều này nếu bạn phải sử dụng công tắc.

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

bạn có thể vui lòng giải thích quá ..?
user1140237

Phạm vi hàm trả về một số giá trị theo đối số đầu vào, do đó, việc phát hiện "phạm vi giá trị" có thể được thực hiện ở đây, cùng với mệnh đề trường hợp chuyển đổi.
zl9394

Đây là làm việc đối với trường hợp sử dụng của tôi, tôi có 2 biến int và tôi muốn kiểm tra được rằng 2 biến là trong cùng một phạm vi tương tự (10-20), (20-30), .... như thế này
Sameer Kazi

Tôi sẽ đề nghị sử dụng một enum thay vì các giá trị int ma thuật.
nmatt

4

Không, bạn không thể làm điều đó. Điều tốt nhất bạn có thể làm là

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

3

Có thể nhóm một số điều kiện trong cùng một casetuyên bố sử dụng cơ chế của mùa thu qua cho phép báo cáo chuyển đổi, nó được đề cập trong hướng dẫn Java và quy định đầy đủ trong phần §14.11. Câu lệnh chuyển đổi của Đặc tả Ngôn ngữ Java .

Đoạn mã sau được lấy từ một ví dụ trong hướng dẫn, nó tính toán số ngày trong mỗi tháng (được đánh số từ tháng 1 đến tháng 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;
}

Như bạn có thể thấy, để bao hàm một loạt các giá trị trong một casecâu lệnh, cách thay thế duy nhất là liệt kê từng giá trị có thể một cách riêng lẻ, nối tiếp nhau. Như một ví dụ bổ sung, đây là cách triển khai mã giả trong câu hỏi:

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

Bạn có thể sử dụng một enumđể đại diện cho phạm vi của mình,

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

Nó được hỗ trợ như Java 12. Hãy xem JEP 354 . Không có khả năng "phạm vi" nào ở đây, nhưng cũng có thể hữu ích.

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

Bạn cũng có thể thực hiện điều đó trên int. Lưu ý rằng câu lệnh switch của bạn phải đầy đủ (sử dụng defaulttừ khóa hoặc sử dụng tất cả các giá trị có thể có trong câu lệnh trường hợp).


3

Đây là một cách đẹp và tối giản để đi

(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");

Bạn có thể giải thích điều này?? - Tôi nhận được 'ifs mini' nhưng khác với idk đó.
Kamin Pallaghy

@Tunaki đây là một giải if..elseifpháp thay thế bằng cách sử dụng toán tử bậc ba ( condition ? statementIfTrue : statementIfFalse) theo tầng.
Williem

2

Câu trả lời của @missingfaktor thực sự đúng nhưng hơi phức tạp. Mã dài hơn (ít nhất là đối với các khoảng thời gian liên tục) thì nó có thể như vậy và yêu cầu quá tải / ép kiểu và / hoặc tham số hóa cho long, float, Integer, v.v.

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
Xin lỗi vì phản hồi muộn, tôi không thể cập nhật SO trả lời gần đây. Tôi sẽ trả lời từng bài phê bình của bạn. 1. Mã dài hơn một chút, vâng, và nó cũng thực hiện một số tính toán thừa. Nhưng IMO đó là hỗ trợ rõ ràng trong trường hợp này. Trong mã của bạn, người ta phải nhớ các trường hợp trước khi một người rơi qua bậc thang.
missfaktor

2
Đối với việc yêu cầu quá tải và phôi, đó không phải là một IMO chỉ trích hợp lệ. Việc Java không có cách nào hợp lý để trừu tượng hóa các kiểu số nói về những hạn chế của Java, nhiều hơn là về cách tiếp cận này. Bạn có thể muốn khám phá Numlớp kiểu của Haskell nếu bạn muốn hiểu rõ hơn về điểm này.
missfaktor

@missingfaktor 1. Tôi đoán đó là vấn đề sở thích. Khi xử lý các khoảng liên tục, cá nhân tôi thích nghĩ về ifs như thể tôi đang dần dần tách ra khỏi dải con thấp hơn. Hơn nữa, một tính toán dư thừa không phải là một vấn đề gì cả, nhưng so sánh dư thừa là một chút lo lắng: nó được đơn giản hơn để so sánh liền kề không đồng nhất, ví dụ như sau khi một số chỉnh sửa: if (isBetween(x, 1, 4)) {...} else if (isBetween(x, 6, 10)). Dù sao, không phải là một vấn đề lớn.
Alexander Malakhov

2. Đồng ý - Hạn chế của Java, nhưng đó là những gì chúng tôi phải làm việc và mã gốc của bạn sẽ được sao chép cho nhiều loại khác nhau. Trong trường hợp cụ thể này, một vấn đề có thể được giảm thiểu bằng cách sử dụng lớp Số , mặc dù cách tiếp cận của Haskell tốt hơn (chưa bao giờ thực sự học Haskell, nhưng nó giống như "Khái niệm ánh sáng" của C ++. Ngoài ra, tôi tin rằng bạn muốn nói Real, không phải vậy Num).
Alexander Malakhov

2

Sử dụng một NavigableMaptriển khai, như 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);

Giải pháp tuyệt vời! đừng quên kiểm tra null bằng cách sử dụng if (messages.floorEntry(value)!=null) nếu bạn sử dụng giá trị Số nguyên
Ch Vas

1
@ChVas Cách bản đồ được thiết lập ở đây, floorEntry()sẽ không bao giờ quay trở lại null(việc chèn Integer.MIN_VALUEkhóa nhằm ngăn chặn điều đó). Tuy nhiên, bất kể loại giá trị của bạn là gì, bạn cần quyết định cách xử lý các khóa nằm ngoài phạm vi hợp lệ.
erickson

0

Đối với số đầu vào trong phạm vi 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

Loại hành vi này không được hỗ trợ trong Java. Tuy nhiên, nếu bạn có một dự án lớn cần điều này, hãy cân nhắc pha trộn mã Groovy trong dự án của bạn. Mã Groovy được biên dịch thành mã byte và có thể chạy với JVM. Công ty tôi đang làm việc sử dụng Groovy để viết các lớp dịch vụ và Java để viết mọi thứ khác.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.