Java switch 문 여러 경우


118

Java switch 문에 여러 사례를 사용하는 방법을 알아 내려고합니다. 다음은 내가하려는 작업의 예입니다.

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

해야 할 일과 비교 :

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

이것이 가능하다면 어떤 아이디어 나 좋은 대안은 무엇입니까?


12
정수를 사용하는 것처럼 보이므로 범위가 고정 된 크기라는 것을 안다면 항상 switch (variable / FIXED_SIZE_OF_RANGE) {case 0 : ... default : break; }
paulrehkugler 2013 년

답변:


80

슬프게도 Java에서는 불가능합니다. if-else문 사용에 의지해야 합니다.


1
@FunJavaCode AFAIK는 vb.net에서 할 수 있습니다. 여기에 예가 있습니다
Bala R

1
@YuryLitvinov가 잘못되었다고 생각하는 이유를 확장하고 싶습니까?
Bala R

1
내 대답은 이것이 정확하지 않다는 것을 증명하고 OO이며 if/elseif/else언어에 관계없이 많은 중첩 된 문 을 필요로하는 다른 사람들의 정확한 문제를 처리하기 위해 알려져 있고 받아 들여지는 패턴입니다 .

1
그것은 이러한 링크를 사용하여 스위치의 경우에는 OR 조건을 얻을 수 있습니다 ... PLZ를 체크 아웃 : - stackoverflow.com/a/16706729/3946958
라빈 드라 Kushwaha

4
bro 그것의 가능한 사용은 break를 사용하지 않고 여러 케이스를 작성할 수 있으며 케이스 끝에 다음과 같은 논리를 작성할 수 있습니다. case some_value : case some_value : case some_value : you_logic_goes_here break;
anoopbryan2 2016-09-09

85

두 번째 옵션은 완전히 괜찮습니다. 응답자가 왜 불가능하다고 말했는지 모르겠습니다. 이것은 괜찮습니다. 저는 항상 이것을합니다.

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

50
질문자는이 일을 "대"라고 말했습니다. 그는 당신이 나열한 것이 타당하다는 것을 이해하고 그 대신 첫 번째 일을하려고했습니다.
Blaine Mucklow 2012-08-31

45
죄송합니다. 동일한 항목으로 이동하는 95 개 케이스를 연속으로 나열하는 것이 어떻게 해결되는지 모르겠습니다. 내가 어떤 코드에서든 그것을 발견하면 그들을 추적하고 납치하고 개인적으로 GLaDOS에 전달하고 그녀가 찾을 수있는 가장 치명적인 테스트 시퀀스를 제공하기를 바랍니다.
animuson

1
그 위에 @animuson, 그는 60 번 upvoted .... 나는 정확한 그가 대답 일은하고 싶지 didnt는 사촌 여기 온
흥을 깨는 사람

이것이 질문에 답하지 않기 때문에 반대 투표. . .heck, 분명히이 답변을 작성하기 위해 질문을 읽지 않았습니다.
iheanyi

50
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


4
그것은 그가 피하고 싶었던 그의 질문의 "대"부분과 동일합니다.
Bdoserror

2
코드 전용 답변은 링크 전용 답변만큼이나 나쁩니다. 그들은 전혀 답이 아닙니다. 좋은 대답에는 설명과 추론, 그리고 아마도 몇 가지 출처 나 권위가 포함됩니다.
markus

3
그것은 아무것도보다 낫다, 어떤 사람들은 가지고있는 최선 대답은 간단하고 직접적인 같은
D4rWiNS

48

이전 답변만큼 우아하지는 않지만 큰 범위가 거의없는 스위치 케이스를 얻으려면 미리 범위를 단일 케이스로 결합하십시오.

// 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.
} 

11
나는 이것을 추천하지 않을 것입니다. 코드를 실행하는 것만으로도을 case 1의미 하는 직관을 갖게 variable == 1되어 장기적으로 혼란과 많은 고통을 겪게됩니다. 코드를 읽을 수 있도록 주석을 추가해야한다면 IMHO를 잘못한 것입니다.
kraxor

21

옵션을 지향 한 개체 과도하게 큰 교체 switchif/else구조는을 사용하는 Chain of Responsibility Pattern의사 결정을 모델링 할 수 있습니다.

책임의 사슬 패턴

책임 체인 패턴을 사용하면 요청에 대해 잠재적으로 많은 수의 핸들러 중 어느 것이 조치를 취해야하는지 결정하는 것으로부터 요청 소스를 분리 할 수 ​​있습니다. 체인 역할을 나타내는 클래스는 핸들러가 요청을 수락하고 조치를 취할 때까지 핸들러 목록을 따라 소스의 요청을 채널링합니다.

다음은 Generics를 사용하는 Type Safe 인 구현의 예입니다.

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

    }
}

이것은 내가 몇 분 만에 채찍질 한 빠른 짚 맨일 뿐이다. 좀 더 정교한 구현은 콜백 IoC 스타일로 만들기 위해 구현 인스턴스 에 어떤 종류의 Command Pattern주입을 허용 할 수 있다 Case.

이 접근 방식에 대한 좋은 점은 Switch / Case 문이 모두 부수적 영향에 관한 것이라는 점입니다. 이것은 부수 효과를 클래스에 캡슐화하여 관리하고 더 잘 재사용 할 수 있도록합니다. 결국 기능적 언어의 패턴 일치와 비슷해집니다. 그것은 나쁜 것이 아닙니다.

Gist 에 대한 업데이트 나 개선 사항을 Github에 게시하겠습니다 .


2
많은 양의 변수가 있으면 case 서술문과 big if 블록이 끔찍합니다. 많은 case 서술문을 작성하고 있다면 OO 원칙을 사용하지 않는 것입니다.
Blaine Mucklow 2012-08-31

11

이 질문 에 따르면 전적으로 가능합니다.

동일한 논리를 포함하는 모든 케이스를 함께 배치하고 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다른 것으로 점프하기 때문 입니다.casebreakreturn

편집하다:

댓글에 답장하면 논리가 동일한 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선택합니다.


2
질문은 이미 이것을 해결책으로 제공하고 범위의 모든 값을 코딩 하지 않고도 범위를 지정하는 방법이 있는지 묻습니다 (OP에는 96 개의 case문 이 필요 합니다!). 수락 된 답변에 동의합니다.
보헤미안

의견 주셔서 감사합니다. 아마도 편집을 참조하십시오. 나는 모든 것이 시나리오에 달려 있다는 데 동의하며 5 대 95는 그렇지 않을 수 있습니다.
WesternGun 2016

6

원래:

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

정말 스위치를 사용해야한다면 특정 범위에 대해 다양한 작업을해야하기 때문일 것입니다. 이 경우, 예, 당신은 복잡한 코드를 갖게 될 것입니다. 왜냐하면 상황이 복잡해지고 패턴을 따르는 것만 잘 압축 될 것이기 때문입니다.

전환의 유일한 이유는 숫자 전환 값을 테스트하는 경우 변수 이름 입력을 절약하기위한 것입니다. 당신은 100 가지를 켜지 않을 것이고, 그들은 모두 같은 일을하지 않을 것입니다. 그것은 'if'청크처럼 들립니다.


4

// 비준수 코드 예제

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

엄지 손가락을 치켜 세울만한 실제 답변. 좋은.
user1735921

3

지난 Java-12 릴리스부터 동일한 케이스 레이블의 여러 상수를 미리보기 언어 기능 에서 사용할 수 있습니다.

실제 사용을 기반으로 개발자 피드백을 유도하기 위해 JDK 기능 릴리스에서 사용할 수 있습니다. 이로 인해 향후 Java SE 플랫폼에서 영구적이 될 수 있습니다.

다음과 같이 보입니다.

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

JEP 325 : 스위치 식 (미리보기) 더보기


2

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수 있습니다.

자세한 내용은 공식 문서 를 참조하십시오 .


1

대안을 위해 다음과 같이 사용할 수 있습니다.

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

    }

또는 다음 코드도 작동합니다.

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

1

JEP 354 : JDK-13 및 JEP 361의 스위치 표현식 (미리보기) : JDK-14의 스위치 표현식 (표준) 스위치 문 을 확장하여 표현식 으로 사용할 수 있습니다.

이제 다음을 수행 할 수 있습니다.

  • 스위치 표현식 에서 직접 변수 할당 ,
  • 새 형식의 스위치 레이블 사용 ( case L ->) :

    "case L->"스위치 레이블의 오른쪽에있는 코드는 표현식, 블록 또는 (편의상) throw 문으로 제한됩니다.

  • 쉼표로 구분하여 대소 문자별로 여러 상수를 사용하십시오.
  • 또한 더 이상 가치 하락 이 없습니다 .

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

0

하드 코딩 된 값을 사용하는 대신 한 가지 대안은 대신 switch 문에 범위 매핑을 사용할 수 있습니다.

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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.