본문 바로가기

Language/JAVA

[JAVA 21] Pattern Matching for switch - 컴도리돌이

728x90

스위치문과 null (switches and null)

전통적으로, switch 문과 표현식은 선택기 표현식이 null을 검증할 때, NullPointerExceptionthrow 합니다. 따라서 null을 테스트하기 위해 switch 바깥에서 테스트해야 했습니다.

// Prior to Java 21
static void testFooBarOld(String s) {
    if (s == null) {
        System.out.println("Oops!");
        return;
    }
    switch (s) {
        case "Foo", "Bar" -> System.out.println("Great");
        default           -> System.out.println("Ok");
    }
}

 

java 21부터는 선택기 표현식의 값이 null일 때 switch의 동작은 항상 case 레이블에 의해 결정됩니다. case null이 있는 경우, switch는 해당 레이블과 관련된 코드를 실행합니다.

 

// As of Java 21
static void testFooBarNew(String s) {
    switch (s) {
        case null         -> System.out.println("Oops");
        case "Foo", "Bar" -> System.out.println("Great");
        default           -> System.out.println("Ok");
    }
}

케이스 미세화(Case reflnement)


패턴을 사용하는 case 레이블은 상수를 사용하는 경우와 달리 많은 값에 적용될 수 있습니다. 이는 종종 switch 규칙의 오른쪽에 조건부 코드를 사용하게 됨을 의미합니다. 

 

// As of Java 21
static void testStringOld(String response) {
    switch (response) {
        case null -> { }
        case String s -> {
            if (s.equalsIgnoreCase("YES"))
                System.out.println("You got it");
            else if (s.equalsIgnoreCase("NO"))
                System.out.println("Shame");
            else
                System.out.println("Sorry?");
        }
    }
}

 

 

여기서의 문제는 단일 패턴을 사용하여 케이스를 구별하는 것이 단일 조건을 넘어 확장되지 않는다는 것입니다. 여러 패턴을 작성하는 것이 좋겠지만, 그러려면 패턴을 세밀하게 표현할 수 있는 방법이 필요합니다. 따라서 switch 블록에서 패턴 case 레이블에 가드를 지정할 수 있는 when 절을 허용합니다. 이러한 접근 방식으로 가드를 사용하여 위의 코드를 다시 작성할 수 있습니다.

 

// As of Java 21
static void testStringNew(String response) {
    switch (response) {
        case null -> { }
        case String s
        when s.equalsIgnoreCase("YES") -> {
            System.out.println("You got it");
        }
        case String s
        when s.equalsIgnoreCase("NO") -> {
            System.out.println("Shame");
        }
        case String s -> {
            System.out.println("Sorry?");
        }
    }
}

 

이로써, switch 프로그래밍의 더 읽기 쉬운 스타일을 이끌어냅니다. 테스트의 복잡성이 switch 규칙의 왼쪽에 나타나고, 해당 테스트가 충족되는 경우 적용되는 로직이 switch 규칙의 오른쪽에 나타납니다. 이를 통해 보다 읽기 좋은 스위치 문 작성이 가능해집니다.

 

// As of Java 21
static void testStringEnhanced(String response) {
    switch (response) {
        case null -> { }
        case "y", "Y" -> {
            System.out.println("You got it");
        }
        case "n", "N" -> {
            System.out.println("Shame");
        }
        case String s
        when s.equalsIgnoreCase("YES") -> {
            System.out.println("You got it");
        }
        case String s
        when s.equalsIgnoreCase("NO") -> {
            System.out.println("Shame");
        }
        case String s -> {
            System.out.println("Sorry?");
        }
    }
}

 

case 상수, case 패턴 및 null 레이블이 조합되어 switch 프로그래밍의 새로운 기능을 보여주며, 비즈니스 로직과 혼합되었던 복잡한 조건 로직을 읽기 쉬운 순차적인 switch 레이블 목록으로 단순화할 수 있음을 보여줍니다.


스위치문과 열거형 상수(Switches and enum constants)

java 21전에는 case문에서 enum 상수를 사용하는 것은 매우 제한적입니다. switch문의 표현식은 enum 유형이어야 하며, 레이블은 enum 상수의 단순한 이름이어야 합니다.

// Prior to Java 21
public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES }

static void testforHearts(Suit s) {
    switch (s) {
        case HEARTS -> System.out.println("It's a heart!");
        default -> System.out.println("Some other suit");
    }
}

 

패턴 레이블을 추가한 후에도, 이 제약은 불필요하게 장황한 코드를 유발합니다.

 

// As of Java 21
sealed interface CardClassification permits Suit, Tarot {}
public enum Suit implements CardClassification { CLUBS, DIAMONDS, HEARTS, SPADES }
final class Tarot implements CardClassification {}

static void exhaustiveSwitchWithoutEnumSupport(CardClassification c) {
    switch (c) {
        case Suit s when s == Suit.CLUBS -> {
            System.out.println("It's clubs");
        }
        case Suit s when s == Suit.DIAMONDS -> {
            System.out.println("It's diamonds");
        }
        case Suit s when s == Suit.HEARTS -> {
            System.out.println("It's hearts");
        }
        case Suit s -> {
            System.out.println("It's spades");
        }
        case Tarot t -> {
            System.out.println("It's a tarot");
        }
    }
}

 

guarded patterns을 사용하는 대신 열거형 상수에 대해 별도의 case문을 사용할 수 있습니다. 따라서 case 표현식이 열거형이어야 한다는 제한 조건을 완화하고 case문에 사용되는 상수가 열거형 상수를 사용할 수 있도록 허용합니다. 이를 통해 위의 코드를 다음과 같이 작성할 수 있습니다.

 

// As of Java 21
static void exhaustiveSwitchWithBetterEnumSupport(CardClassification c) {
    switch (c) {
        case Suit.CLUBS -> {
            System.out.println("It's clubs");
        }
        case Suit.DIAMONDS -> {
            System.out.println("It's diamonds");
        }
        case Suit.HEARTS -> {
            System.out.println("It's hearts");
        }
        case Suit.SPADES -> {
            System.out.println("It's spades");
        }
        case Tarot t -> {
            System.out.println("It's a tarot");
        }
    }
}

 

이제 guarded type patterns을 사용하지 않고도 각 enum 상수에 대한 직접적인 case문을 사용할 수 있습니다.


 

JEP 441: Pattern Matching for switch

JEP 441: Pattern Matching for switch OwnerGavin BiermanTypeFeatureScopeSEStatusClosed / DeliveredRelease21Componentspecification / languageDiscussionamber dash dev at openjdk dot orgRelates toJEP 433: Pattern Matching for switch (Fourth Preview)Rev

openjdk.org