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)
{
c
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;
}
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.
Sadly, it's not possible in Java. You'll have to resort to using if-else
statements.
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:
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.
To yield a value from a switch expression, the
break
with value statement is dropped in favor of ayield
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);
}
}
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.
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