Java开关语句有多种情况

试图找出如何使用Java switch语句的多个情况。 以下是我想要做的一个例子:

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

与必须这样做:

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

任何想法,如果这可能,或者一个好的select是什么?

不幸的是,这在Java中是不可能的。 你将不得不诉诸使用if-else语句。

第二个选项是完全正确的。 我不确定响应者为什么说这是不可能的。 这很好,我一直这样做:

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

也许不像以前的答案那样优雅,但是如果你想要实现less量大范围的开关情况,只需将范围结合到一个单一的案例:

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

date:

 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

一个面向对象的选项来取代过大的switchif/else结构是使用Chain of Responsibility Pattern来模拟决策。

责任链模式

责任链模式允许将请求源分离,以决定请求中可能大量的处理程序中的哪一个应该处理该请求。 表示链式angular色的类沿着处理程序列表传递来自源的请求,直到处理程序接受请求并对其执行操作。

下面是一个使用genericstypes安全的示例实现。

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

这只是我在几分钟内匆匆而过的一个快速的解决scheme,一个更复杂的实现可能允许将某种Command Pattern注入到Case实例中,使其更多地callbackIoC样式。

一旦这种方法的好处是Switch / Case语句都是关于副作用的,那么这些副作用就会被封装在Classes中,这样它们就可以被pipe理,并且被更好地重用,最终更像是函数式语言中的模式匹配这不是一件坏事。

我将在Github上发布任何更新或增强function。

基本上:

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

如果你真的需要使用开关,那将是因为你需要为特定范围做各种事情。 在这种情况下,是的,你将会有乱七八糟的代码,因为事情变得越来越复杂,只有遵循模式的东西才能压缩。

如果您只是testing数字切换值,则切换的唯一原因是保存inputvariables名称。 你不会接通100件事情,而且也不会全都做同样的事情。 这听起来更像是一个“如果”大块。

根据这个问题 ,这是完全可能的。

把所有包含相同逻辑的情况放在一起,不要把它们放在后面。

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

这是因为没有breakcase下会跳到另一个case直到breakreturn

编辑:

回复评论,如果我们确实有95个具有相同逻辑的值,但具有不同逻辑的情况数量less得多,我们可以这样做:

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

如果你需要更好的控制, if-else是select。

有可能使用Vavr库来处理这个问题

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

Match是一个expression式,所以它在这里返回类似于Runnable实例,而不是直接调用方法。 匹配完成后,可以执行Runnable

有关更多详情,请参阅官方文档 。

//不符合的代码示例

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

//兼容解决scheme

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