Java switch statement multiple cases
Asked Answered
C

16

155

Just trying to figure out how to use many multiple cases for a Java switch statement. Here's an example of what I'm trying to do:

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

versus having to do:

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

Any ideas if this possible, or what a good alternative is?

Croze answered 23/2, 2011 at 2:17 Comment(1)
It looks like you're using integers so I suppose if you know that your ranges are of a fixed size you could always do switch(variable / FIXED_SIZE_OF_RANGE){ case 0: ... default: break; }Mccandless
V
91

Sadly, it's not possible in Java. You'll have to resort to using if-else statements.

Vowelize answered 23/2, 2011 at 2:20 Comment(15)
@Croze AFAIK you can do that in vb.net . Here's an exampleVowelize
Groovy allows this too, and I think Pascal has also a similar syntax.Rauch
My answer proves this is incorrect, it is OO and is a known and accepted pattern for dealing with this exact problem amoungst others that require many nested if/elseif/else statements, regardless of language.Garish
@JarrodRoberson Although I think the Chain of responsibility pattern is very good. The question was specific to the switch pattern. And the code you posted in the end has ifs too. So how the answer is wrong?Incantatory
its not about not using if or switch it is about using if or switch statements with dozens or hundreds of alternatives cases. The question specifically asks for a good alternative, my answer is the most relevant and OO answer so far.Garish
I thought the answer was just fine.Tropho
It is possible to get the OR condition in the SWITCH case by using these link...plz check it out:- https://mcmap.net/q/80341/-using-two-values-for-one-switch-case-statementSpherule
bro its possible use can write multiple case without using break and at the end of case you can write your logic like: case some_value: case some_value: case some_value: you_logic_goes_here break;Thenceforth
@Croze Kotlin has it too, which is compatible with Java. kotlinlang.org/docs/reference/control-flow.html#when-expressionSentience
You must be kidding me, its very much possible to do it. Simple don't apply a break in the end. Your answer is misleading.Gasman
Swift has it too. 'case 1 ... 100', or case 1 ..< 101.Cichocki
Golang also have it. tour.golang.org/flowcontrol/11 (9, 10 and 11 pages)Moderation
Why is this the accepted answer? this operation is totally possible in JavaUndervest
It is possible using multiple switch cases see my answerEnisle
It's possible in Java 19, see my answer https://mcmap.net/q/110902/-java-switch-statement-multiple-casesCreaturely
M
107

The second option is completely fine. I'm not sure why a responder said it was not possible. This is fine, and I do this all the time:

switch (variable)
{
    case 5:
    case 6:
    etc.
    case 100:
        doSomething();
    break;
}
Maiga answered 11/3, 2011 at 20:3 Comment(6)
The questioner said do this "versus" doing this. He understands that what you listed is valid, he was trying to do the first thing INSTEAD of that.Precautious
I'm sorry, but I don't see how listing out 95 cases in a row that go to the same thing is a solution to anything. If I encountered that in any code I would track them down, kidnap them, deliver them personally to GLaDOS, and hope she gives them the deadliest sequence of tests she can find.Gynecologist
@Gynecologist on top of which, he gets upvoted 60 times....go figure. I came here coz I didnt want to do the EXACT thing he answersHauger
Downvoting as this does not answer the question. . .heck, apparently, the question wasn't even read in order to write this answer.Bierman
This is a nightmare, how can people upvote that that much ?Cinchonism
@Cinchonism welcome to stackoverflow.. no one reads the questions (nor the answers it seems), they just rush in answering to get pointsSadonia
V
91

Sadly, it's not possible in Java. You'll have to resort to using if-else statements.

Vowelize answered 23/2, 2011 at 2:20 Comment(15)
@Croze AFAIK you can do that in vb.net . Here's an exampleVowelize
Groovy allows this too, and I think Pascal has also a similar syntax.Rauch
My answer proves this is incorrect, it is OO and is a known and accepted pattern for dealing with this exact problem amoungst others that require many nested if/elseif/else statements, regardless of language.Garish
@JarrodRoberson Although I think the Chain of responsibility pattern is very good. The question was specific to the switch pattern. And the code you posted in the end has ifs too. So how the answer is wrong?Incantatory
its not about not using if or switch it is about using if or switch statements with dozens or hundreds of alternatives cases. The question specifically asks for a good alternative, my answer is the most relevant and OO answer so far.Garish
I thought the answer was just fine.Tropho
It is possible to get the OR condition in the SWITCH case by using these link...plz check it out:- https://mcmap.net/q/80341/-using-two-values-for-one-switch-case-statementSpherule
bro its possible use can write multiple case without using break and at the end of case you can write your logic like: case some_value: case some_value: case some_value: you_logic_goes_here break;Thenceforth
@Croze Kotlin has it too, which is compatible with Java. kotlinlang.org/docs/reference/control-flow.html#when-expressionSentience
You must be kidding me, its very much possible to do it. Simple don't apply a break in the end. Your answer is misleading.Gasman
Swift has it too. 'case 1 ... 100', or case 1 ..< 101.Cichocki
Golang also have it. tour.golang.org/flowcontrol/11 (9, 10 and 11 pages)Moderation
Why is this the accepted answer? this operation is totally possible in JavaUndervest
It is possible using multiple switch cases see my answerEnisle
It's possible in Java 19, see my answer https://mcmap.net/q/110902/-java-switch-statement-multiple-casesCreaturely
C
67
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;
            }
        }
    }
}

Out:

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

Calculus answered 11/1, 2013 at 23:7 Comment(3)
That is the same as the "versus" part of his question, which he wanted to avoid.Honniball
Code only answers are almost as bad as link only answers. They're not really answers at all. A good answer contains explanations and reasoning and possibly some sources or authority.Re
It is better than nothing, some people take that as the best answer, simple and directLegionnaire
A
51

Maybe not as elegant as some previous answers, but if you want to achieve switch cases with few large ranges, just combine ranges to a single case beforehand:

// 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.
} 
Ajar answered 29/12, 2011 at 6:51 Comment(1)
I wouldn't recommend this. If you just run through the code, you will have the intuition that case 1 means variable == 1, which leads to confusion and a lot of pain in the long run. If you need to place comments in your code to make it readable, then you did something wrong IMHO.Onagraceous
G
23

One Object Oriented option to replace excessively large switch and if/else constructs is to use a Chain of Responsibility Pattern to model the decision making.

Chain of Responsibility Pattern

The chain of responsibility pattern allows the separation of the source of a request from deciding which of the potentially large number of handlers for the request should action it. The class representing the chain role channels the requests from the source along the list of handlers until a handler accepts the request and actions it.

Here is an example implementation that is also Type Safe using 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);

    }
}

This is just a quick straw man that I whipped up in a few minutes, a more sophisticated implementation might allow for some kind of Command Pattern to be injected into the Case implementations instances to make it more of a call back IoC style.

Once nice thing about this approach is that Switch/Case statements are all about side affects, this encapsulates the side effects in Classes so they can be managed, and re-used better, it ends up being more like Pattern Matching in a Functional language and that isn't a bad thing.

I will post any updates or enhancements to this Gist on Github.

Garish answered 23/2, 2011 at 4:1 Comment(1)
I agree, case statements and big if blocks are nasty if you have a large amount of variables. If you are doing a lot of case statements then you aren't using OO principles as well as you could be.Precautious
I
22

This is possible with switch enhancements in Java 14. Following is a fairly intuitive example of how the same can be achieved.

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");
}
Invective answered 4/1, 2021 at 8:7 Comment(0)
G
17

According to this question, it's totally possible.

Just put all cases that contain the same logic together, and don't put break behind them.

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

It's because case without break will jump to another case until break or return.

EDIT:

Replying the comment, if we really have 95 values with the same logic, but a way smaller number of cases with different logic, we can do:

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 you need finer control, if-else is the choice.

Greenhouse answered 24/8, 2016 at 12:42 Comment(2)
The question already offers this as a solution and asks if there's a way to specify a range without having to code every value in the range (OP would require 96 case statements!). I'm afraid I agree with the accepted answer.Dudek
Thanks for comment. See edit, maybe. I agree that it all depends on the scenario, and 5 vs 95 may not be the case.Greenhouse
T
9

JEP 354: Switch Expressions (Preview) in JDK-13 and JEP 361: Switch Expressions (Standard) in JDK-14 will extend the switch statement so it can be used as an expression.

Now you can:

  • directly assign variable from switch expression,
  • use new form of switch label (case L ->):

    The code to the right of a "case L ->" switch label is restricted to be an expression, a block, or (for convenience) a throw statement.

  • use multiple constants per case, separated by commas,
  • and also there are no more value breaks:

    To yield a value from a switch expression, the break with value statement is dropped in favor of a yield statement.

Switch expression example:

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

Timberland answered 9/2, 2020 at 10:48 Comment(0)
W
7

From the last java-12 release multiple constants in the same case label is available in preview language feature

It is available in a JDK feature release to provoke developer feedback based on real world use; this may lead to it becoming permanent in a future Java SE Platform.

It looks like:

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

See more JEP 325: Switch Expressions (Preview)

Waive answered 27/3, 2019 at 20:28 Comment(0)
A
6

Basically:

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

If you really needed to use a switch, it would be because you need to do various things for certain ranges. In that case, yes, you're going to have messy code, because things are getting complex and only things which follow patterns are going to compress well.

The only reason for a switch is to save on typing the variable name if you're just testing for numeric switching values. You aren't going to switch on 100 things, and they aren't going to be all doing the same thing. That sounds more like an 'if' chunk.

Adagietto answered 5/2, 2013 at 17:31 Comment(0)
A
4

// Noncompliant Code Example

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

//Compliant Solution

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();
}
Aec answered 25/9, 2017 at 20:7 Comment(1)
The actual Answer which deserved thumbs up. Nice.Gasman
L
2

It is possible to handle this using Vavr library

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

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

This is of course only slight improvement since all cases still need to be listed explicitly. But it is easy to define custom predicate:

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 is an expression so here it returns something like Runnable instance instead of invoking methods directly. After match is performed Runnable can be executed.

For further details please see official documentation.

Lussier answered 19/9, 2017 at 15:10 Comment(0)
E
2

One alternative instead of using hard-coded values could be using range mappings on the the switch statement instead:

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;
}
Exocarp answered 14/5, 2019 at 4:56 Comment(0)
M
1

for alternative you can use as below:

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

    }

or the following code also works

switch (variable)
{
    case 5:
    case 6:
    etc.
    case 100:
        doSomething();
    break;
}
Menashem answered 18/5, 2018 at 15:51 Comment(0)
C
1

JEP 427: Pattern Matching for switch (Third Preview) arrived as a preview feature in Java 19, and allows you to solve the problem with a so called "guarded patten":

Integer variable = new Random().nextInt(200);
switch (variable) {
     case Integer v when v >= 5 && v <= 100
             -> System.out.println("in my range");
     default -> System.out.println("out of range");
}

Hot to enable preview Features in your Java, see this SO-Question.

By Java 20 or 21, this syntax will probably be available as a standard feature.

Creaturely answered 14/3, 2023 at 8:37 Comment(0)
E
-2

I found a solution to this problem... We can use multiple conditions in switch cases in java.. but it require multiple switch cases..

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;
                }
        }
        
    }
}
}
Enisle answered 12/12, 2021 at 17:58 Comment(1)
Your solution uses three tenary operators and three switches for a problem that could be solved with an (ugly but arguably better) if-else chain.Horselaugh

© 2022 - 2024 — McMap. All rights reserved.