[Java] Switch ~ case Expression After JDK14

728x90

 

평소에 Switch ~ case 구조를 잘 안사용할 것이라는 착각을 했지만 가끔 사용을 하기도 했고 JDK14 이후 변환이 있다길래 공부한 내용을 포스팅 해보려고 합니다

 

Java 버전이 업그레이드 됨에 따라 생기는 새로운 기능들을 사용하려고 할 때 실무 관점에서 계속 고민하게 되는 포인트가 있습니다.

 

Java 버전이 빠르게 발전하면서 추가되고 바뀌는 문법을 적용하는게 무조건 가독성 향상 및 유지보수에 편할까? 라는 고민도을 계속합니다.

요즘 클린 코드 를 공부하다보니 '실무' 와 '클린 코드' 사이에서의 뭔가 고민이 되는 포인트가 많이 있었습니다.

일단 지금 회사에서는 내가 뭔가 새로운 것을 쓰면 다 설명을 해줘야 한다. 사람들한테...

왜 먼저 찾아보지 않고 질문을 할까라는 생각도 하지만 일단 그런 이야기는 pass~

 

 

JDK 14 이전 vs JDK 14 이후

JDK 14 이전

  • 불필요한 반복코드가 사용됨
  • 다수의 case, break 를 써야함
  • break 안쓰면 case 끝까지 요청이감.

JDK 14 이후

  • 람다식으로 표현도 가능
  • 단일 수행 또는 블록 수행이 가능하다.
  • switch 블록 내에서 계산된 값을 반환하는 yield 라는 키워드가 생김
  • 여러 조건을 쉼표로 구분하여 한 라인으로 처리하기 가능

 

한번 예시를 보자

enum Days { 
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;
}

 

switch 내부에 input 을 정의한 Enum 클래스이다

 

아래 코드는 반환값이 없을 때 코드 예시이다.

    @Test
    void beforeJDK14 () {

        String day = Days.MONDAY.name();

        String result = switch (day) {
            case "MONDAY":
                System.out.println(Days.MONDAY.getDescription());
                break;
            case "TUESDAY":
                System.out.println(Days.TUESDAY.getDescription());
                break;
            case "WEDNESDAY":
                System.out.println(Days.WEDNESDAY.getDescription());
                break;
            case "THURSDAY":
                System.out.println(Days.THURSDAY.getDescription());
                break;
            case "FRIDAY":
                System.out.println(Days.FRIDAY.getDescription());
                break;
            case "SATURDAY":
                System.out.println(Days.SATURDAY.getDescription());
                break;
            case "SUNDAY":
                System.out.println(Days.SUNDAY.getDescription());
                break;
            default:
                System.out.println("그만 탈출한다 switch ~ case");
        };

    }

 

위 코드는 JDK 12 이전에 사용하던, switch ~ case 방식으로 저거 치는대 조금 손가락이 귀찮았다

 


개발자라면 코드를 최대한 덜 치면서 기능을 만들고 싶어할테니 그래서 나온게 JDK 12 이후에 람다 방식 switch ~ case 이다

    @Test
    void usedLambdaSwitchCase() {
        String day = Days.MONDAY.name();

        // break 가 포함되어 있음 안써도 댐 이젠
        switch (day) {
            case "MONDAY" -> System.out.println(Days.MONDAY.getDescription());
            case "TUESDAY" -> System.out.println(Days.TUESDAY.getDescription());
            case "WEDNESDAY" -> System.out.println(Days.WEDNESDAY.getDescription());
            case "THURSDAY" -> System.out.println(Days.THURSDAY.getDescription());
            case "FRIDAY" -> System.out.println(Days.FRIDAY.getDescription());
            case "SATURDAY" -> System.out.println(Days.SATURDAY.getDescription());
            case "SUNDAY" -> System.out.println(Days.SUNDAY.getDescription());
            default -> System.out.println("탈출 ㅋ");
        }

    }

 

그래도 break 도 사라지고 나름 아까보다는 깔끔해졌다.

하지만 실무에서는 위 같은 방식보다는 어떠한 값을 분기처리해서 가져올 떄 사용할 것 이다


그리고 System.out 보다는 log 방식을 채용할 수 밖에 없을 것이고 그래서 아래와 같은 코드 형태가 되야한다.

@Test
void usedLambdaSwitchCase() {
    String day = Days.MONDAY.name();

    // 변수가 생김
    String today = switch (day) {
        case "MONDAY" -> Days.MONDAY.getDescription();
        case "TUESDAY" -> Days.TUESDAY.getDescription();
        case "WEDNESDAY" -> Days.WEDNESDAY.getDescription();
        case "THURSDAY" -> Days.THURSDAY.getDescription();
        case "FRIDAY" -> Days.FRIDAY.getDescription();
        case "SATURDAY" -> Days.SATURDAY.getDescription();
        case "SUNDAY" -> Days.SUNDAY.getDescription();
        default -> "그만 탈출한다 switch ~ case";
    };
}

 

즉 리턴되는 값이 today 라는 변수에저장이 되는 것이고 위 로직을 통해 분기처리를 할 수 있다.

간단한 값을 리턴하는 단일 수행일 경우 위와 같은 코드를 작성해야 하지만 만약 단일 수행이 아니라 다른 처리가 더 필요하다면?
그럴 떄는 JDK 14 에 나온 'yield' 라는 키워드를 사용할 수도 있다.

 

그럼 이전에는 어떻게 여러개의 case 안에서 추가 로직을 사용했을까?

 


바로 맨 처음 봤던 코드처럼 사용을 했다

String description;

switch(day){
    case Monday:
        description = "월요일";
        // 필요하다면 분기 로직 더 처리
        break;
}

 

대충 위와 같은 코드였지만, 그걸 좀더 깔끔하게 정리를 한게 아래와 같은 코드이다.

 

이제는 아래와 같이 조금더 좋게 사용을 해보자!

@Test
void usedYieldSwitchCase() {
    String day = Days.MONDAY.name();

    String description = switch (day) {
        case "MONDAY" -> {
            log.info("아 시간 겁나 안가네");
            yield Days.MONDAY.getDescription();
            // System.out.println("시간이 안가.."); -> yield 이후로는 로직 작성 불가
        }
        case "TUESDAY" -> Days.TUESDAY.getDescription();
        case "WEDNESDAY" -> Days.WEDNESDAY.getDescription();
        case "THURSDAY" -> Days.THURSDAY.getDescription();
        case "FRIDAY" -> Days.FRIDAY.getDescription();
        case "SATURDAY" -> Days.SATURDAY.getDescription();
        case "SUNDAY" -> Days.SUNDAY.getDescription();
        default -> {
            yield "탈출 ㅋ"; // 복잡한 로직을 처리하는 경우 유용
        }
    };

}

 

 

참고로 yield 는 항상 switch 블록 내부에서만 사용할 수 있다. 아래 예시를 보자

String today = switch (day) {
    case MONDAY -> "월요일!";
    case TUESDAY -> yield "화요일"; // yield는 block {} 안에서만 사용가능 -> 즉 에러남 
    case WEDNESDAY -> { yield "수요일";} // 이런 방식으로 사용해야함
    // ~~~
    default -> "탈출";
};


즉 단순 반환일 경우 '람다(->)' 사용, 추가 로직 필요시 'yield' 사용
그리고 자동 break 처리 또한 되기 때문에 편하다.

 

둘을 차이를 정리해보자면

  • JDK 14 이전
    • 외부 변수 선언 후 값 할당
    • break 필요
    • 가독성 상대적으로 복잡
    • 각 케이스에서 외부 변수 조작
  • JDK 14 이후
    • 외부 변수 없이 yield 를 통한 값 반환
    • break 불 필요
    • 가독성 좋음 -> 코드가 간결하기 때문
    • 각 케이스별로 yield 를 통한 반환값 직접 처리

 

 

JDK 14 이후로 yield 를 통해 값을 반환하면서 흐름 제어를 자동으로 처리하므로 더 간결하고, switch 표현식을 효율적으로 사용할 수 있게 되었다.

마지막 고민은 새로운 기능을 사용한 코드를 나중에 코드 리뷰 받으면 우리 어르신 형님들이 어떻게 생각할지 고민임.. 이상

 

 

 

728x90