Java switch语句多种情况

Fun*_*ode 108 java syntax switch-statement

只是想弄清楚如何在Java switch语句中使用多个案例.这是我正在尝试做的一个例子:

switch (variable)
{
    case 5..100:
        doSomething();
    break;
}
Run Code Online (Sandbox Code Playgroud)

与必须做的:

switch (variable)
{
    case 5:
    case 6:
    etc.
    case 100:
        doSomething();
    break;
}
Run Code Online (Sandbox Code Playgroud)

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

Bal*_*a R 78

可悲的是,这在Java中是不可能的.你将不得不求助于使用if-else陈述.

  • 我的回答证明这是不正确的,它是面向对象的,并且是一种已知且可接受的模式,用于处理其他需要许多嵌套“if/elseif/else”语句的确切问题,无论语言如何。 (3认同)
  • 兄弟可能的用法可以在不使用break的情况下编写多个case,在最后的情况下你可以编写你的逻辑:case some_value:case some_value:case some_value:you_logic_goes_here break; (3认同)
  • 是的,Pascal有它. (2认同)

小智 77

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

switch (variable)
{
    case 5:
    case 6:
    etc.
    case 100:
        doSomething();
    break;
}
Run Code Online (Sandbox Code Playgroud)

  • 提问者说这样做"对抗"这样做.他知道你列出的内容是有效的,他试图做的第一件事就是INSTEAD. (47认同)
  • 对不起,但我不知道连续95个案例列出同样的东西是如何解决任何问题.如果我在任何代码中遇到它,我会追踪它们,绑架它们,将它们个人交给GLaDOS,并希望她给她们一个她能找到的最致命的测试序列. (38认同)
  • @animuson 除此之外,他还被点赞了 60 次……算算吧。我来这里是因为我不想做他回答的事情 (3认同)
  • @animuson您的评论已被[赞赏](http://roflcopter.pl/7414). (2认同)
  • 这真是一场噩梦,人们怎么能投票那么多呢? (2认同)

小智 47

也许不像之前的一些答案那样优雅,但是如果你想要实现几个大范围的开关盒,只需事先将范围组合到一个案例中:

// 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.
} 
Run Code Online (Sandbox Code Playgroud)

  • 我不推荐这个.如果你只是运行代码,你会直觉"case 1"的意思是"变量== 1",从长远来看会导致混乱和很多痛苦.如果您需要在代码中添加注释以使其可读,那么您做错了恕我直言. (9认同)

P. *_*man 45

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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

日期:

Default case
First case
First case
First case
First case
Default case
Default case
Default case
Second case
Second case
Run Code Online (Sandbox Code Playgroud)

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

  • 这与他想要避免的问题的"对比"部分相同. (4认同)
  • 它总比没有好,有些人认为这是最好的答案,简单而直接 (3认同)
  • 仅代码答案几乎与仅链接答案一样糟糕.他们根本不是真正的答案.一个好的答案包含解释和推理,可能还有一些来源或权威. (2认同)

Ris*_*shi 22

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

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");
}
Run Code Online (Sandbox Code Playgroud)


小智 20

替换过大switchif/else构造的一个面向对象的选项是使用a 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);

    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 我同意,如果你有大量的变量,case语句和大if块是讨厌的.如果您正在做大量的案例陈述,那么您就不会使用OO原则. (2认同)

Isk*_*der 9

JEP 354: JDK-13 中的Switch 表达式(预览)和JEP 361: JDK-14 中的 Switch 表达式(标准)将扩展switch 语句,以便它可以用作表达式

现在你可以:

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

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

  • 每种情况使用多个常量,用逗号分隔,
  • 并且也没有更多的价值中断

    为了从 switch 表达式中产生一个值,breakwith 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);
  }
}

Run Code Online (Sandbox Code Playgroud)


小智 6

基本上:

if (variable >= 5 && variable <= 100)
{
    doSomething();
}
Run Code Online (Sandbox Code Playgroud)

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

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


Wes*_*Gun 6

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

只需将所有包含相同逻辑的案例放在一起,不要将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;
}
Run Code Online (Sandbox Code Playgroud)

这是因为,case如果没有,break它将跳到另一个,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;
}
Run Code Online (Sandbox Code Playgroud)

如果需要更好的控制,if-else则是选择。

  • 这个问题已经提供了解决方案,并询问是否有一种方法可以指定一个范围,而不必*对该范围内的每个值进行编码(OP将需要96个“ case”语句!)。恐怕我同意接受的答案。 (2认同)

Rus*_*lan 6

从最新的 java-12 版本开始,预览语言功能中可以使用同一 case 标签中的多个常量

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

看起来像:

switch(variable) {
    case 1 -> doSomething();
    case 2, 3, 4 -> doSomethingElse();
};
Run Code Online (Sandbox Code Playgroud)

查看更多JEP 325:切换表达式(预览)