在每种情况下都使用带有范围值的switch语句?


91

在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中是否有类似的东西?还是应该只使用ifelse if语句?


甚至在纯C中都有扩展允许这样做。
arshajii

Answers:


97

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
这很好用,很简单。另外,如果您要选择不在此范围内的数字,则只需要if(!isBetween ...,干得好
。– a54studio

1
@missingfaktor我批评了您的回答。因此,您可能想要回复一些内容。+1。
亚历山大·马拉霍夫

@MCEmperor,请不要使用您的个人格式设置来编辑我的答案。这不是有用的编辑。
missingfaktor

@missingfaktor抱歉。但是该编辑很久以前就被批准了;我什至不记得我曾经这样做过。
MC Emperor

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一起工作。–
Stefan,

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:
     //
}

9

我知道这篇文章很旧,但是我相信这个答案值得认可。无需避免使用switch语句。这可以在Java中完成,但可以通过switch语句来完成,而不是通过case来完成。它涉及使用三元运算符。

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":
Daniel Widdis

@DanielWiddis:我建议使用枚举而不是字符串,以确保一致性。
nmatt

@nmatt通常同意。我试图允许使用“ 1 .. 5”样式的语法。
丹尼尔·威迪斯

2
@DanielWiddis:肯定是一件好事;我将枚举常量命名为FROM_1_TO_5之类的名称。通常,范围具有特定含义,在这种情况下,可以根据范围的含义来命名枚举常量。
nmatt

1
我想我们可以同意任何一个选项是优于0,1,或2
丹尼尔Widdis

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

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

函数范围根据输入参数返回一些值,因此可以在此处执行“值范围”检测,并结合switch case子句。
zl9394 '16

这适用于我的用例,我有2个int变量,我要检查的是2个变量在相同的范围内,例如(10-20),(20-30),....像这样
Sameer Kazi

我建议使用枚举而不是魔术int值。
nmatt

5

或者,您可以按预期使用单独的案例,并使用默认案例将范围说明指定为:

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

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节中完全指定switch语句中的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

您可以使用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;
  }
}

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.代码有点冗长,是的,它还进行了一些冗余计算。但是,在这种情况下,海事组织正在帮助澄清。在您的代码中,当人们跌入阶梯时,必须记住以前的情况。
missingfaktor 2014年

2
至于要求重载和强制转换,这不是对IMO的有效批评。Java没有明智的方法来抽象数字类型,这说明了Java的局限性,而不仅仅是这种方法。Num如果您想更好地理解这一点,则可能需要探索Haskell的类型类。
missingfaktor 2014年

@missingfaktor 1.我想这是一个品味问题。在处理连续间隔时,我个人喜欢将ifs好像是我逐渐从较低的子范围溢出一样。此外,冗余计算根本不是问题,但是冗余比较有点令人担忧:例如,进行一些编辑后,使相邻比较不同步变得更简单if (isBetween(x, 1, 4)) {...} else if (isBetween(x, 6, 10))。无论如何,没什么大不了的。
亚历山大·马拉霍夫

2.同意-Java的局限性,但这是我们必须使用的限制,并且您的原始代码将复制为各种类型。在这种特殊情况下,可以通过使用Number类来缓解问题,尽管Haskell的方法更好(从来没有真正学习过Haskell,但是它类似于C ++的“ Concepts Light”。而且,我相信您的意思Real不是Num)。
亚历山大·马拉霍夫

2

这是一种美丽而简约的方式

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

你能解释一下吗?-我确实得到了'mini ifs',但除了idk。
Kamin Pallaghy

@Tunaki这是if..elseif在级联中使用三元操作符(condition ? statementIfTrue : statementIfFalse)的替代方法。
威利姆,2016年

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) 如果您使用Integer值,请不要忘记检查是否为空
Ch Vas

1
@ChVas此处设置地图的方式floorEntry()将永远不会返回null(插入Integer.MIN_VALUE键是为了防止这种情况)。但是,无论您使用哪种值类型,都需要决定如何处理有效范围之外的键。
erickson

2

从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关键字,或在case语句中使用所有可能的值)。


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编写其他所有东西。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.