본문으로 건너뛰기
안동민 개발노트 아이콘

안동민 개발노트

본문 시작
4장 : 제어문

switch 문과 switch 식

하나의 값에 따라 여러 동작을 고를 때 긴 if-else보다 switch가 구조를 잘 드러낼 수 있습니다.

전통적인 콜론 문법은 break를 빠뜨리면 다음 case까지 실행되는 fall-through가 발생합니다.

화살표 규칙과 switch 식은 한 case의 경계를 명확히 하고 값을 직접 반환합니다.

열거형이나 제한된 상태를 분기할 때 특히 유용합니다.

이 절에서는 문과 식의 차이, 그리고 모든 경우를 다루는 방법을 살펴봅니다.


콜론 case는 fall-through를 허용한다

여러 case가 같은 처리를 공유할 때 의도적으로 사용할 수 있지만 실수로 break를 빠뜨리기 쉽습니다.

의도한 fall-through에는 주석을 남기는 편이 좋습니다.


화살표 규칙은 한 case의 경계를 닫는다

case A -> 형식은 다음 case로 흘러가지 않습니다.

여러 라벨을 쉼표로 묶을 수 있어 같은 처리도 짧게 표현합니다.

예제에서는 회원 등급을 입력으로 받아 사용 한도를 만듭니다. 콜론 case의 흐름 제어보다 화살표 규칙과 switch 식이 “등급 하나에서 한도 하나”라는 관계를 어떻게 드러내는지에 집중합니다.

enum 자체는 9장에서 자세히 다룹니다. 지금은 GUEST, MEMBER, ADMIN이라는 가능한 입력이 세 개로 고정돼 있어 switch가 모든 경우를 빠짐없이 다룰 수 있다는 점만 사용합니다.

SwitchExpression.java
public class SwitchExpression {
    enum Level { GUEST, MEMBER, ADMIN }

    static int quota(Level level) {
        return switch (level) {
            case GUEST -> 1;
            case MEMBER -> 10;
            case ADMIN -> {
                int auditedQuota = 100;
                yield auditedQuota;
            }
        };
    }

    public static void main(String[] args) {
        for (Level level : Level.values()) {
            System.out.println(level + "=" + quota(level));
        }
    }
}

화살표 case는 한 규칙이 끝난 뒤 다음 case로 흘러가지 않으므로 break를 빠뜨릴 여지가 없습니다. 여러 값이 같은 결과라면 case SATURDAY, SUNDAY ->처럼 입력만 묶어 분기 경계를 유지합니다.

GUEST=1
MEMBER=10
ADMIN=100

enum의 모든 상수를 나열해 default 없이도 완전한 switch 식이 됩니다.

선택자 값 평가

switch 괄호 안의 값을 한 번 계산합니다. 이 값의 타입이 가능한 case 집합과 null 처리 방식을 정합니다.

일치하는 case 하나 선택

화살표 규칙은 일치한 case의 식이나 블록 하나만 실행합니다. 여러 입력이 같은 결과라면 쉼표로 case 레이블을 묶습니다.

화살표 식 또는 yield로 값 반환

짧은 case는 화살표 뒤의 값이 결과가 되고, 여러 문장이 필요한 블록은 yield로 결과를 냅니다. 모든 가능한 상태가 값을 제공해야 switch 식 전체의 타입이 결정됩니다.


switch 식은 분기 결과를 값으로 만든다

각 분기가 같은 타입의 값을 제공하며 여러 문장이 필요하면 블록과 yield를 사용합니다.

변수를 먼저 선언하고 case마다 대입하는 코드를 줄일 수 있습니다.

값을 계산하려는 분기라면 각 case에서 변수에 대입한 뒤 빠져나오기보다 switch 식의 결과를 바로 받는 편이 낫습니다. 블록이 필요한 case에서는 yield가 switch 전체가 돌려줄 값을 정하며, 메서드를 끝내는 return과 역할이 다릅니다.

비교 1
int day = 2;
switch (day) {
    case 1:
    case 2:
        System.out.println("weekday");
        break; // 빠뜨리면 다음 case로 흐를 수 있음
    default:
        System.out.println("other");
}
비교 2
// quota(null); // 실행 시 NullPointerException

가능한 상태를 빠짐없이 다룬다

enum을 모두 나열하면 새 상수가 추가될 때 컴파일러가 누락을 알려 줄 수 있습니다.

닫힌 상태 집합에서는 무조건 default를 넣는 것이 오히려 변경 감지를 막을 수 있습니다.


null 처리는 분기 계약에 포함한다

참조 선택자가 null이면 일반 switch는 예외가 날 수 있습니다.

호출 전에 금지하거나 명시적으로 처리하는 정책을 정합니다.


분기 안의 부작용보다 값을 반환한다

switch 식이 계산한 결과를 다음 코드에서 사용하면 각 case가 무엇을 만드는지 비교하기 쉽습니다.

출력과 필드 변경을 case마다 섞지 않습니다.

분기마다 파일을 쓰거나 외부 상태를 바꾸기 시작하면 어떤 값이 선택되었는지와 부작용 성공 여부가 섞입니다. switch는 우선 명령이나 정책 값을 고르게 하고, 실제 작업은 분기 밖의 한 지점에서 실행하도록 나누면 실패 처리가 단순해집니다.


switch는 값의 가능한 상태가 분명할 때 사용하고, 새 상태 추가를 컴파일러가 감지하도록 가능한 한 완전한 분기를 작성합니다.