Оператор переключения Java несколько случаев - PullRequest
100 голосов
/ 23 февраля 2011

Просто пытаюсь понять, как использовать многократные случаи для оператора переключения Java. Вот пример того, что я пытаюсь сделать:

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

против необходимости:

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

Есть идеи, если это возможно, или какая хорошая альтернатива?

Ответы [ 12 ]

73 голосов
/ 11 марта 2011

Второй вариант вполне подойдет. Я не уверен, почему ответчик сказал, что это невозможно. Это хорошо, и я делаю это все время:

switch (variable)
{
    case 5:
    case 6:
    etc.
    case 100:
        doSomething();
    break;
}
71 голосов
/ 23 февраля 2011

К сожалению, это невозможно в Java. Вам придется прибегнуть к использованию if-else операторов.

45 голосов
/ 29 декабря 2011

Возможно, не так элегантно, как в некоторых предыдущих ответах, но если вы хотите добиться переключений с несколькими большими диапазонами, просто заранее объедините диапазоны в один случай:

// 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.
} 
41 голосов
/ 12 января 2013
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

20 голосов
/ 23 февраля 2011

Один объектно-ориентированный вариант для замены чрезмерно больших конструкций switch и if/else заключается в использовании Chain of Responsibility Pattern для моделирования процесса принятия решения.

Схема цепочки ответственности

Цепочка ответственности позволяет разделение источника запрос от решения, какой из потенциально большое количество обработчиков для запроса должно действовать это. класс, представляющий роль цепи направляет запросы от источника вдоль списка обработчиков, пока обработчик принимает запрос и действия это.

Вот пример реализации, которая также является типом 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.

6 голосов
/ 05 февраля 2013

В основном:

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

Если вам действительно нужно использовать переключатель, это может быть связано с тем, что вам нужно выполнять различные действия для определенных диапазонов. В этом случае, да, у вас будет грязный код, потому что все становится сложным, и только вещи, которые следуют шаблонам, будут хорошо сжиматься.

Единственная причина переключения - экономия на вводе имени переменной, если вы просто проверяете числовые значения переключения. Вы не собираетесь включать 100 вещей, и они не собираются делать все то же самое. Это больше похоже на блок «если».

5 голосов
/ 24 августа 2016

Согласно этому вопросу , это вполне возможно.

Просто сложите все дела, содержащие одну и ту же логику, и не ставьте 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 является выбором.

4 голосов
/ 25 сентября 2017

// Пример несовместимого кода

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();
}
1 голос
/ 27 марта 2019

Начиная с последнего выпуска java-12, несколько констант в одном и том же регистре доступны в функция языка предварительного просмотра

В версии JDK она доступна, чтобы вызывать отзывы разработчиковосновано на реальном использовании;это может привести к тому, что она станет постоянной в будущей платформе Java SE.

Это выглядит следующим образом:

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

Подробнее JEP 325: выражения выражений (предварительный просмотр)

1 голос
/ 18 мая 2018

для альтернативы вы можете использовать как показано ниже:

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

    }

или следующий код также работает

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