본문으로 건너뛰기
Advertisement

4.3 Switch 표현식과 패턴 매칭 (Java 14+)

자바 14부터 기존 switch 문이 대대적으로 업그레이드되었습니다. 이제 switch는 단순한 문(Statement) 이 아니라 값을 반환하는 표현식(Expression) 으로도 사용할 수 있습니다. 자바 21에서는 패턴 매칭까지 지원하여 더욱 강력해졌습니다.

1. 기존 switch 문의 문제점

기존 switchbreak를 빠뜨리면 다음 case까지 실행되는 fall-through 버그가 발생하기 쉬웠습니다.

// ❌ 기존 방식 - fall-through 버그 위험
int day = 2;
String dayName;

switch (day) {
case 1:
dayName = "월요일";
break; // 이걸 빠뜨리면 다음 case로 넘어가버림!
case 2:
dayName = "화요일";
break;
case 3:
dayName = "수요일";
break;
default:
dayName = "기타";
}

2. Switch 표현식 (Java 14+) - 화살표(->) 문법

새로운 화살표 문법은 break 없이도 fall-through 없이 각 case가 독립적으로 동작합니다. 그리고 값을 직접 반환 할 수 있습니다.

// ✅ 새로운 방식 - 간결하고 안전!
int day = 2;
String dayName = switch (day) {
case 1 -> "월요일";
case 2 -> "화요일";
case 3 -> "수요일";
case 4 -> "목요일";
case 5 -> "금요일";
case 6 -> "토요일";
case 7 -> "일요일";
default -> "잘못된 요일";
};

System.out.println(dayName); // 화요일

여러 case를 하나로 묶기

int day = 6;
String type = switch (day) {
case 1, 2, 3, 4, 5 -> "평일"; // 쉼표로 여러 case 묶기
case 6, 7 -> "주말";
default -> "잘못된 요일";
};

System.out.println(type); // 주말

3. yield 키워드 - 블록 내에서 값 반환

화살표 뒤에 여러 줄의 코드가 필요할 때는 { } 블록을 사용하고, yield 키워드로 값을 반환합니다.

int score = 85;
String grade = switch (score / 10) {
case 10, 9 -> "A";
case 8 -> {
System.out.println("잘 했어요! B등급입니다.");
yield "B"; // 블록 안에서는 yield로 반환
}
case 7 -> "C";
case 6 -> "D";
default -> {
System.out.println("분발해주세요!");
yield "F";
}
};

System.out.println("등급: " + grade); // 등급: B

4. instanceof 패턴 매칭 (Java 16+)

기존에는 instanceof 검사 후 별도로 캐스팅해야 했습니다. 이제는 한 번에 검사와 변수 선언을 할 수 있습니다.

// ❌ 기존 방식 (3단계)
Object obj = "Hello, Java!";
if (obj instanceof String) { // 1. 타입 확인
String s = (String) obj; // 2. 수동 캐스팅
System.out.println(s.length()); // 3. 사용
}

// ✅ 패턴 매칭 (Java 16+) - 1단계로!
if (obj instanceof String s) { // 검사 + 캐스팅 + 변수 선언 동시에!
System.out.println(s.length()); // s를 바로 사용
}

실전 예제: 다양한 도형의 넓이 계산

sealed interface Shape permits Circle, Rectangle, Triangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}
record Triangle(double base, double height) implements Shape {}

public class PatternMatchingExample {
static double getArea(Shape shape) {
if (shape instanceof Circle c) {
return Math.PI * c.radius() * c.radius();
} else if (shape instanceof Rectangle r) {
return r.width() * r.height();
} else if (shape instanceof Triangle t) {
return 0.5 * t.base() * t.height();
}
throw new IllegalArgumentException("알 수 없는 도형");
}

public static void main(String[] args) {
System.out.println(getArea(new Circle(5))); // 78.53...
System.out.println(getArea(new Rectangle(4, 6))); // 24.0
System.out.println(getArea(new Triangle(3, 8))); // 12.0
}
}

5. Switch를 이용한 패턴 매칭 (Java 21)

자바 21에서는 switch 표현식에서 타입 패턴 매칭이 정식 지원됩니다! instanceof 체인 없이 한 번에 타입별 처리가 가능합니다.

static String describe(Object obj) {
return switch (obj) {
case Integer i -> "정수: " + i;
case Double d -> "실수: " + d;
case String s -> "문자열 (길이 " + s.length() + "): " + s;
case int[] arr -> "int 배열 (길이 " + arr.length + ")";
case null -> "null 값";
default -> "알 수 없는 타입: " + obj.getClass().getName();
};
}

public static void main(String[] args) {
System.out.println(describe(42)); // 정수: 42
System.out.println(describe(3.14)); // 실수: 3.14
System.out.println(describe("Hello")); // 문자열 (길이 5): Hello
System.out.println(describe(null)); // null 값
}

가드 조건 (Guarded Patterns) - Java 21

case 조건에 when 절로 추가 조건을 걸 수 있습니다.

static String classifyNumber(Object obj) {
return switch (obj) {
case Integer i when i < 0 -> "음수: " + i;
case Integer i when i == 0 -> "영(0)";
case Integer i when i > 0 -> "양수: " + i;
case Double d when d.isNaN() -> "NaN (숫자 아님)";
default -> "정수/실수 아님";
};
}

System.out.println(classifyNumber(-5)); // 음수: -5
System.out.println(classifyNumber(0)); // 영(0)
System.out.println(classifyNumber(42)); // 양수: 42

고수 팁

switch 표현식을 쓸 때 주의할 점:

  • switch 표현식은 모든 가능한 경우를 처리해야 합니다. default가 없으면 컴파일 에러가 납니다.
  • String, enum, 정수형 타입, wrapper 타입, 그리고 Java 21부터는 모든 Object를 switch할 수 있습니다.
  • enum + switch 표현식 조합은 실무에서 가장 자주 쓰이는 패턴입니다. enum에 새 상수를 추가하면 컴파일러가 처리 안 된 case를 바로 알려줍니다.
enum Season { SPRING, SUMMER, AUTUMN, WINTER }

Season season = Season.SUMMER;
int avgTemp = switch (season) {
case SPRING -> 15;
case SUMMER -> 30;
case AUTUMN -> 18;
case WINTER -> -2;
// default 없어도 됨 - 모든 enum 값이 처리되므로
};
Advertisement