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 -&gt;):

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

每个案例使用多个常量,用逗号分隔, 而且没有更多的价值breaks

为了从 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;

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

编辑:

回复评论,如果我们真的有 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 需要 96 case声明!)。恐怕我同意接受的答案。 感谢您的评论。见编辑,也许。我同意这一切都取决于场景,而 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】:

替换过大的switchif/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 语句多例的主要内容,如果未能解决你的问题,请参考以下文章

java中单例和多例的区别

web 单例 多例

单例与多例的理解

单例和多例的区别

单例和多例的区别

单例和多例的区别