Java switch语句多种情况

时间:2011-02-23 02:17:23

标签: java syntax switch-statement

试图找出如何为Java switch语句使用多个案例。以下是我正在尝试做的一个例子:

switch (variable)
{
    case 5..100:
        doSomething();
    break;
}

与必须做的事情:

switch (variable)
{
    case 5:
    case 6:
    etc.
    case 100:
        doSomething();
    break;
}

任何想法,如果可能,或者有什么好的选择?

14 个答案:

答案 0 :(得分:72)

第二种选择完全没问题。我不确定为什么响应者说不可能。这很好,我一直这样做:

switch (variable)
{
    case 5:
    case 6:
    etc.
    case 100:
        doSomething();
    break;
}

答案 1 :(得分:71)

可悲的是,这在Java中是不可能的。您将不得不求助于使用if-else语句。

答案 2 :(得分:45)

可能没有以前的答案那么优雅,但是如果你想要实现几个大范围的开关案例,只需事先将范围组合到一个案例中:

// make a switch variable so as not to change the original value
int switchVariable = variable;

//combine range 1-100 to one single case in switch
if(1 <= variable && variable <=100)
    switchVariable = 1;
switch (switchVariable) 
{ 
    case 0:
        break; 
    case 1:
        // range 1-100
        doSomething(); 
        break;
    case 101: 
        doSomethingElse(); 
        break;
    etc.
} 

答案 3 :(得分:38)

public class SwitchTest {
    public static void main(String[] args){
        for(int i = 0;i<10;i++){
            switch(i){
                case 1: case 2: case 3: case 4: //First case
                    System.out.println("First case");
                    break;
                case 8: case 9: //Second case
                    System.out.println("Second case");
                    break;
                default: //Default case
                    System.out.println("Default case");
                    break;
            }
        }
    }
}

输出:

Default case
First case
First case
First case
First case
Default case
Default case
Default case
Second case
Second case

Src:http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html

答案 4 :(得分:20)

替换过大的switchif/else构造的一个面向对象的选项是使用Chain of Responsibility Pattern来为决策建模。

责任链模式

  

责任链模式   允许分离的来源   要求决定哪一个   潜在的大量处理程序   对于请求应该采取行动。该   代表连锁角色的类   引导来自源的请求   沿着处理程序列表直到a   handler接受请求和   采取行动。

以下是使用Generics进行类型安全的示例实现。

import java.util.ArrayList;
import java.util.List;

/**
* Generic enabled Object Oriented Switch/Case construct
* @param <T> type to switch on
*/
public class Switch<T extends Comparable<T>>
{
    private final List<Case<T>> cases;

    public Switch()
    {
        this.cases = new ArrayList<Case<T>>();
    }

    /**
     * Register the Cases with the Switch
     * @param c case to register
     */
    public void register(final Case<T> c) { this.cases.add(c); }

    /**
     * Run the switch logic on some input
     * @param type input to Switch on
     */
    public void evaluate(final T type)
    {
        for (final Case<T> c : this.cases)
        {
            if (c.of(type)) { break; }
        }
    }

    /**
     * Generic Case condition
     * @param <T> type to accept
     */
    public static interface Case<T extends Comparable<T>>
    {
        public boolean of(final T type);
    }

    public static abstract class AbstractCase<T extends Comparable<T>> implements Case<T>
    {
        protected final boolean breakOnCompletion;

        protected AbstractCase()
        {
            this(true);
        }

        protected AbstractCase(final boolean breakOnCompletion)
        {
            this.breakOnCompletion = breakOnCompletion;
        }
    }

    /**
     * Example of standard "equals" case condition
     * @param <T> type to accept
     */
    public static abstract class EqualsCase<T extends Comparable<T>> extends AbstractCase<T>
    {
        private final T type;

        public EqualsCase(final T type)
        {
            super();
            this.type = type;
        }

        public EqualsCase(final T type, final boolean breakOnCompletion)
        {
            super(breakOnCompletion);
            this.type = type;
        }
    }

    /**
     * Concrete example of an advanced Case conditional to match a Range of values
     * @param <T> type of input
     */
    public static abstract class InRangeCase<T extends Comparable<T>> extends AbstractCase<T>
    {
        private final static int GREATER_THAN = 1;
        private final static int EQUALS = 0;
        private final static int LESS_THAN = -1;
        protected final T start;
        protected final T end;

        public InRangeCase(final T start, final T end)
        {
            this.start = start;
            this.end = end;
        }

        public InRangeCase(final T start, final T end, final boolean breakOnCompletion)
        {
            super(breakOnCompletion);
            this.start = start;
            this.end = end;
        }

        private boolean inRange(final T type)
        {
            return (type.compareTo(this.start) == EQUALS || type.compareTo(this.start) == GREATER_THAN) &&
                    (type.compareTo(this.end) == EQUALS || type.compareTo(this.end) == LESS_THAN);
        }
    }

    /**
     * Show how to apply a Chain of Responsibility Pattern to implement a Switch/Case construct
     *
     * @param args command line arguments aren't used in this example
     */
    public static void main(final String[] args)
    {
        final Switch<Integer> integerSwitch = new Switch<Integer>();
        final Case<Integer> case1 = new EqualsCase<Integer>(1)
        {
            @Override
            public boolean of(final Integer type)
            {
                if (super.type.equals(type))
                {
                    System.out.format("Case %d, break = %s\n", type, super.breakOnCompletion);
                    return super.breakOnCompletion;
                }
                else
                {
                    return false;
                }
            }
        };
        integerSwitch.register(case1);
        // more instances for each matching pattern, granted this will get verbose with lots of options but is just
        // and example of how to do standard "switch/case" logic with this pattern.
        integerSwitch.evaluate(0);
        integerSwitch.evaluate(1);
        integerSwitch.evaluate(2);


        final Switch<Integer> inRangeCaseSwitch = new Switch<Integer>();
        final Case<Integer> rangeCase = new InRangeCase<Integer>(5, 100)
        {
            @Override
            public boolean of(final Integer type)
            {
                if (super.inRange(type))
                {
                    System.out.format("Case %s is between %s and %s, break = %s\n", type, this.start, this.end, super.breakOnCompletion);
                    return super.breakOnCompletion;
                }
                else
                {
                    return false;
                }
            }
        };
        inRangeCaseSwitch.register(rangeCase);
        // run some examples
        inRangeCaseSwitch.evaluate(0);
        inRangeCaseSwitch.evaluate(10);
        inRangeCaseSwitch.evaluate(200);

        // combining both types of Case implementations
        integerSwitch.register(rangeCase);
        integerSwitch.evaluate(1);
        integerSwitch.evaluate(10);

    }
}

这只是我在几分钟内掀起的一个快速的人,一个更复杂的实现可能允许将某种Command Pattern注入到Case实现实例中以使其更多回调IoC风格。

关于这种方法的好处是Switch / Case语句都是关于副作用的,它将副作用封装在Classes中,这样它们可以被管理,并且可以更好地重复使用,最终更像是模式匹配功能语言,这不是一件坏事。

我将在Github上发布此Gist的任何更新或增强功能。

答案 5 :(得分:6)

基本上:

if (variable >= 5 && variable <= 100)
{
    doSomething();
}

如果你真的需要使用开关,那将是因为你需要为某些范围做各种事情。在那种情况下,是的,你将会遇到混乱的代码,因为事情变得越来越复杂,只有遵循模式的东西才能很好地压缩。

如果您只是测试数字切换值,切换的唯一原因是保存输入变量名称。你不会打开100件事,他们也不会做同样的事情。这听起来更像是'if'块。

答案 6 :(得分:5)

根据this question,它完全有可能。

只需将包含相同逻辑的所有案例放在一起,并且不要将break置于其后。

switch (var) {
    case (value1):
    case (value2):
    case (value3):
        //the same logic that applies to value1, value2 and value3
        break;
    case (value4):
        //another logic
        break;
}

这是因为没有case的{​​{1}}会在breakcase之前跳转到另一个break

编辑:

回复评论,如果我们确实有95个具有相同逻辑的值,但是具有不同逻辑的案例数量较少,我们可以这样做:

return

如果您需要更好的控制,switch (var) { case (96): case (97): case (98): case (99): case (100): //your logic, opposite to what you put in default. break; default: //your logic for 1 to 95. we enter default if nothing above is met. break; } 是您的选择。

答案 7 :(得分:4)

//不合规代码示例

switch (i) {
  case 1:
    doFirstThing();
    doSomething();
    break;
  case 2:
    doSomethingDifferent();
    break;
  case 3:  // Noncompliant; duplicates case 1's implementation
    doFirstThing();
    doSomething();
    break;
  default:
    doTheRest();
}

if (a >= 0 && a < 10) {
  doFirstThing();

  doTheThing();
}
else if (a >= 10 && a < 20) {
  doTheOtherThing();
}
else if (a >= 20 && a < 50) {
  doFirstThing();
  doTheThing();  // Noncompliant; duplicates first condition
}
else {
  doTheRest();
}

//合规解决方案

switch (i) {
  case 1:
  case 3:
    doFirstThing();
    doSomething();
    break;
  case 2:
    doSomethingDifferent();
    break;
  default:
    doTheRest();
}

if ((a >= 0 && a < 10) || (a >= 20 && a < 50)) {
  doFirstThing();
  doTheThing();
}
else if (a >= 10 && a < 20) {
  doTheOtherThing();
}
else {
  doTheRest();
}

答案 8 :(得分:3)

这可以通过 Java 14 中的开关增强功能实现。下面是一个相当直观的示例,说明如何实现相同的效果。

extension IterableMapIndex<T> on Iterable<T> {
  Iterable<E> mapIndexed<E>(E f(int index, T t)) {
    return Iterable.generate(this.length, (index)=>f(index, elementAt(index)));
  }
}

答案 9 :(得分:2)

JDK-13中的

JEP 354: Switch Expressions (Preview)和JDK-14中的JEP 361: Switch Expressions (Standard)将扩展 switch语句 ,因此可以将其用作 表达式

现在您可以:

  • 直接从开关表达式
  • 分配变量
  • 使用新形式的开关标签(case L ->):

    “ case L->”开关标签右侧的代码仅限于表达式,块或(为方便起见)throw语句。

  • 每种情况下均使用多个常量,以逗号分隔,
  • ,也没有更多的休息时间

    要从switch表达式中产生一个值,请删除带有值语句的break,而推荐使用yield语句。

切换表达式示例:

public class SwitchExpression {

  public static void main(String[] args) {
      int month = 9;
      int year = 2018;
      int numDays = switch (month) {
        case 1, 3, 5, 7, 8, 10, 12 -> 31;
        case 4, 6, 9, 11 -> 30;
        case 2 -> {
          if (java.time.Year.of(year).isLeap()) {
            System.out.println("Wow! It's leap year!");
            yield 29;
          } else {
            yield 28;
          }
        }
        default -> {
          System.out.println("Invalid month.");
          yield 0;
        }
      };
      System.out.println("Number of Days = " + numDays);
  }
}

答案 10 :(得分:1)

可以使用Vavr

来处理此问题
grep -v Makefile

这当然只是略有改进,因为所有案例仍然需要明确列出。但是定义自定义谓词很容易:

import static io.vavr.API.*;
import static io.vavr.Predicates.*;

Match(variable).of(
    Case($(isIn(5, 6, ... , 100)), () -> doSomething()),
    Case($(), () -> handleCatchAllCase())
);

匹配是一个表达式,因此它返回类似public static <T extends Comparable<T>> Predicate<T> isInRange(T lower, T upper) { return x -> x.compareTo(lower) >= 0 && x.compareTo(upper) <= 0; } Match(variable).of( Case($(isInRange(5, 100)), () -> doSomething()), Case($(), () -> handleCatchAllCase()) ); 实例的内容,而不是直接调用方法。执行匹配后,可以执行Runnable

有关详细信息,请参阅official documentation

答案 11 :(得分:1)

替代方案,您可以使用如下:

if (variable >= 5 && variable <= 100) {
        doSomething();

    }

或以下代码也可以使用

switch (variable)
{
    case 5:
    case 6:
    etc.
    case 100:
        doSomething();
    break;
}

答案 12 :(得分:1)

从最近的Java-12版本开始,preview language feature中的相同大小写标签中有多个常量

  

JDK功能版本中提供了该功能,以根据实际使用情况激发开发人员反馈。这可能会导致它在将来的Java SE平台中永久存在。

它看起来像:

switch(variable) {
    case 1 -> doSomething();
    case 2, 3, 4 -> doSomethingElse();
};

查看更多JEP 325: Switch Expressions (Preview)

答案 13 :(得分:0)

一种替代使用硬编码值的替代方法可以是在switch语句上使用范围映射:

private static final int RANGE_5_100 = 1;
private static final int RANGE_101_1000 = 2;
private static final int RANGE_1001_10000 = 3;

public boolean handleRanges(int n) {
    int rangeCode = getRangeCode(n);
    switch (rangeCode) {
        case RANGE_5_100: // doSomething();
        case RANGE_101_1000: // doSomething();
        case RANGE_1001_10000: // doSomething();
        default: // invalid range
    }
}

private int getRangeCode(int n) {
    if (n >= 5 && n <= 100) {
        return RANGE_5_100;
    } else if (n >= 101 && n <= 1000) {
        return RANGE_101_1000;
    } else if (n >= 1001 && n <= 10000) {
        return RANGE_1001_10000;
    }

    return -1;
}