Ответ 1
К сожалению, это невозможно в Java. Вам придётся использовать выражения if-else
.
Просто попытаюсь выяснить, как использовать много разных случаев для оператора Java. Вот пример того, что я пытаюсь сделать:
switch (variable)
{
case 5..100:
doSomething();
break;
}
по сравнению с тем, что нужно сделать:
switch (variable)
{
case 5:
case 6:
etc.
case 100:
doSomething();
break;
}
Любые идеи, если это возможно, или какая хорошая альтернатива?
К сожалению, это невозможно в Java. Вам придётся использовать выражения if-else
.
Второй вариант полностью прекрасен. Я не знаю, почему ответчик сказал, что это невозможно. Это прекрасно, и я делаю это все время:
switch (variable)
{
case 5:
case 6:
etc.
case 100:
doSomething();
break;
}
Может быть, не так элегантно, как некоторые предыдущие ответы, но если вы хотите добиться случаев переключения с несколькими большими диапазонами, просто объедините диапазоны в один случай заранее:
// 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.
}
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
Src: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
Один объектно-ориентированный вариант для замены чрезмерно больших конструкций switch
и if/else
заключается в использовании Chain of Responsibility Pattern
для моделирования принятия решений.
Цепочка ответственности
Цепочка ответственности позволяет разделить источник просьба о принятии решения о том, какая из потенциально большое количество обработчиков поскольку запрос должен действовать. класс, представляющий роль цепочки направляет запросы от источника по списку обработчиков до обработчик принимает запрос и его действия.
Вот пример реализации, который также является Type Safe с использованием 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);
}
}
Это всего лишь быстрый человек соломы, который я взбивал через несколько минут, более сложная реализация может позволить ввести какой-то Command Pattern
в экземпляры реализаций Case
, чтобы сделать его более обратным Стиль IoC.
Как только приятная вещь об этом подходе заключается в том, что операторы Switch/Case относятся ко всем аспектам побочных эффектов, они инкапсулируют побочные эффекты в классах, поэтому их можно управлять и снова использовать лучше, они в конечном итоге больше похожи на соответствие шаблонов в Функциональный язык, и это не плохо.
Я опубликую любые обновления или улучшения для этого Gist в Github.
В принципе:
if (variable >= 5 && variable <= 100)
{
doSomething();
}
Если вам действительно нужно использовать переключатель, это будет потому, что вам нужно делать разные вещи для определенных диапазонов. В таком случае, да, у вас будет грязный код, потому что все становится сложным, и только вещи, которые следуют шаблонам, будут хорошо сжиматься.
Единственная причина для переключения - сохранить при вводе имени переменной, если вы просто проверяете числовые значения переключения. Вы не собираетесь включать 100 вещей, и они не собираются делать то же самое. Это больше похоже на кусок "если".
По этому вопросу это вполне возможно.
Просто соедините все кейсы, содержащие одну и ту же логику, и не ставьте перед ними 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;
}
Это потому, что case
без break
перейдет к другому 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
выбор - выбор.
//Несоответствующий пример кода
switch (i) {
case 1:
doFirstThing();
doSomething();
break;
case 2:
doSomethingDifferent();
break;
case 3: // Noncompliant; duplicates case 1 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();
}
С этим можно справиться, используя Vavr библиотека
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
.
Подробнее см. официальная документация.
для альтернативы вы можете использовать, как показано ниже:
if (variable >= 5 && variable <= 100) {
doSomething();
}
или следующий код также работает
switch (variable)
{
case 5:
case 6:
etc.
case 100:
doSomething();
break;
}
Начиная с последнего выпуска java-12, несколько констант в одной и той же метке доступны в функции предварительного просмотра.
Он доступен в выпуске функций JDK для обеспечения обратной связи с разработчиками на основе реального использования; это может привести к тому, что она станет постоянной в будущей платформе Java SE.
Это выглядит как:
switch(variable) {
case 1 -> doSomething();
case 2, 3, 4 -> doSomethingElse();
};
См. Больше JEP 325: выражения Выражения (Предварительный просмотр)
Одной из альтернатив может быть моделирование диапазонов в виде диапазонов кода:
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;
}