Java switch 语句多例
Posted
技术标签:
【中文标题】Java switch 语句多例【英文标题】:Java switch statement multiple cases 【发布时间】:2011-07-02 11:04:10 【问题描述】:只是想弄清楚如何为 Java switch 语句使用多种情况。这是我正在尝试做的一个示例:
switch (variable)
case 5..100:
doSomething();
break;
与必须做的:
switch (variable)
case 5:
case 6:
etc.
case 100:
doSomething();
break;
如果可能的话,有什么想法,或者有什么好的替代方案?
【问题讨论】:
看起来你正在使用整数,所以我想如果你知道你的范围是固定大小的,你总是可以做 switch(variable / FIXED_SIZE_OF_RANGE) case 0: ... default: break ; 【参考方案1】:我找到了解决这个问题的办法……我们可以在java的switch case中使用多个条件……但是它需要多个switch case……
public class MultiCSwitchTest
public static void main(String[] args)
int i = 209;
int a = 0;
switch (a = (i>=1 && i<=100) ? 1 : a)
case 1:
System.out.println ("The Number is Between 1 to 100 ==> " + i);
break;
default:
switch (a = (i>100 && i<=200) ? 2 : a)
case 2:
System.out.println("This Number is Between 101 to 200 ==> " + i);
break;
default:
switch (a = (i>200 && i<=300) ? 3 : a)
case 3:
System.out.println("This Number is Between 201 to 300 ==> " + i);
break;
default:
// You can make as many conditions as you want;
break;
【讨论】:
【参考方案2】:这可以通过 Java 14 中的开关增强功能实现。以下是一个相当直观的示例,说明如何实现相同的目标。
switch (month)
case 1, 3, 5, 7, 8, 10, 12 -> System.out.println("this month has 31 days");
case 4, 6, 9 -> System.out.println("this month has 30 days");
case 2 -> System.out.println("February can have 28 or 29 days");
default -> System.out.println("invalid month");
【讨论】:
【参考方案3】: JDK-13 中的JEP 354: Switch Expressions (Preview) 和 JDK-14 中的 JEP 361: Switch Expressions (Standard) 将扩展 switch 语句,因此它可以用作 表达。
现在你可以:
直接从switch 表达式中赋值变量, 使用新形式的开关标签(case L ->
):
每个案例使用多个常量,用逗号分隔, 而且没有更多的价值breaks:“case L ->”开关标签右侧的代码被限制为表达式、块或(为方便起见)throw 语句。
为了从 switch 表达式中产生一个值,
break
with value 语句被删除,取而代之的是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);
【讨论】:
【参考方案4】:一种替代使用硬编码值的替代方法是在 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;
【讨论】:
【参考方案5】:从上一个 java-12 版本开始,preview language feature 中提供了同一 case 标签中的多个常量
它在 JDK 功能版本中提供,可根据实际使用情况激发开发人员的反馈;这可能会导致它在未来的 Java SE 平台中成为永久性的。
看起来像:
switch(variable)
case 1 -> doSomething();
case 2, 3, 4 -> doSomethingElse();
;
查看更多JEP 325: Switch Expressions (Preview)
【讨论】:
【参考方案6】:根据this question,完全有可能。
只要把所有包含相同逻辑的case放在一起,不要把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;
这是因为没有break
的case
会跳转到另一个case
直到break
或return
。
编辑:
回复评论,如果我们真的有 95 个逻辑相同的值,但逻辑不同的情况要少得多,我们可以这样做:
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
是您的选择。
【讨论】:
这个问题已经提供了这个解决方案,并询问是否有办法指定一个范围而不必编码范围中的每个值(OP 需要 96case
声明!)。恐怕我同意接受的答案。
感谢您的评论。见编辑,也许。我同意这一切都取决于场景,而 5 对 95 可能并非如此。【参考方案7】:
您可以使用如下替代方法:
if (variable >= 5 && variable <= 100)
doSomething();
或者下面的代码也可以使用
switch (variable)
case 5:
case 6:
etc.
case 100:
doSomething();
break;
【讨论】:
【参考方案8】:// 不合规代码示例
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();
【讨论】:
值得竖起大拇指的实际答案。不错。【参考方案9】:可以使用Vavr library 来处理这个问题
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 是一个表达式,所以这里它返回类似Runnable
实例的东西,而不是直接调用方法。匹配后Runnable
可以执行。
更多详情请查看official documentation。
【讨论】:
【参考方案10】:可能没有之前的一些答案那么优雅,但是如果你想实现几个大范围的切换案例,只需事先将范围组合成一个案例:
// 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.
【讨论】:
我不推荐这个。如果你只是运行代码,你会直觉case 1
意味着variable == 1
,从长远来看这会导致混乱和很多痛苦。如果您需要在代码中放置 cmets 以使其可读,那么恕我直言,您做错了什么。【参考方案11】:
遗憾的是,这在 Java 中是不可能的。您将不得不求助于使用if-else
语句。
【讨论】:
@FunJavaCode AFAIK 你可以在 vb.net 中做到这一点。这是example @YuryLitvinov 你想扩大你认为不正确的原因吗? 我的回答证明这是不正确的,它是面向对象的,并且是一种已知且公认的模式,用于处理需要许多嵌套if/elseif/else
语句的其他问题,无论语言如何。
可以通过以下链接获得 SWITCH 案例中的 OR 条件...请检查一下:- ***.com/a/16706729/3946958
兄弟它可能的用途可以编写多个案例而不使用中断,并且在案例结束时您可以编写您的逻辑,例如: case some_value: case some_value: case some_value: you_logic_goes_here break;【参考方案12】:
基本上:
if (variable >= 5 && variable <= 100)
doSomething();
如果您真的需要使用开关,那是因为您需要为特定范围做各种事情。在这种情况下,是的,你的代码会很乱,因为事情变得越来越复杂,只有遵循模式的事情才能很好地压缩。
切换的唯一原因是如果您只是测试数字切换值,则可以节省键入变量名称的时间。你不会打开 100 件事情,他们也不会都做同样的事情。这听起来更像是一个“如果”块。
【讨论】:
【参考方案13】: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
源:http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
【讨论】:
这与他的问题中的“对”部分相同,这是他想避免的。 仅代码答案几乎与仅链接答案一样糟糕。它们根本不是真正的答案。一个好的答案包含解释和推理,可能还有一些来源或权威。 总比没有好,有些人认为这是最好的答案,简单直接【参考方案14】:第二个选项完全没问题。我不确定为什么响应者说不可能。这很好,我一直这样做:
switch (variable)
case 5:
case 6:
etc.
case 100:
doSomething();
break;
【讨论】:
提问者说这样做“与”这样做。他知道您列出的内容是有效的,他正试图做第一件事而不是这样做。 我很抱歉,但我看不出连续列出 95 个用于同一件事的案例是解决任何问题的方法。如果我在任何代码中遇到这种情况,我会追踪他们,绑架他们,亲自将他们交给 GLaDOS,并希望她给他们她能找到的最致命的测试序列。 @animuson 最重要的是,他获得了 60 次投票......我来这里是因为我不想做他回答的确切的事情 投反对票,因为这不能回答问题。 . .哎呀,显然,为了写这个答案,甚至没有读过这个问题。【参考方案15】:替换过大的switch
和if/else
构造的一个面向对象选项是使用Chain of Responsibility Pattern
来对决策进行建模。
责任链模式
责任链模式 允许分离源 决定哪一个的请求 潜在的大量处理程序 因为请求应该采取行动。这 代表链角色的类 引导来自源的请求 沿着处理程序列表直到 处理程序接受请求并 操作它。
这是一个使用泛型的类型安全的示例实现。
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 语句都是关于副作用的,这将副作用封装在类中以便可以管理和更好地重复使用,它最终更像是模式匹配函数式语言,这不是一件坏事。
我会在 Github 上发布对此 Gist 的任何更新或改进。
【讨论】:
我同意,如果你有大量变量,case 语句和大 if 块是讨厌的。如果你做了很多案例陈述,那么你就没有尽可能地使用 OO 原则。以上是关于Java switch 语句多例的主要内容,如果未能解决你的问题,请参考以下文章