본문 바로가기

Languages

[Kotlin] switch to when with enum

자바의 switch는 when으로 변경할 수 있다.

자바의 switch는 문(statement)이지만 코틀린의 when은 식(expression)이다.

 

코들린의 When을 쓰면서 좋은 점은 enum에 대한 분기를 할 때 default를 넣지 않아도 된다는 것이다.

예를들어 아래와 같은 2대 통신사의 열거형이 있다고 하면,

public enum Telecom {
    SKT,
    KT,
}

어떤 처리기를 만들어주는 팩토리를 구현을 할 때 아래와 같이 만든다면 switch 끝의 라인에 에러를 만난다.

interface TelecomHandler {
    void handle();
}

class TelecomFactory {
    public TelecomHandler create(Telecom telecom) {
        switch (telecom) {
            case KT:
                return new SktHandler();
            case SKT:
                return new KtHandler();
        }
    }
}

에러 메시지

error: missing return statement
}
^

이것은 자바 언어차원에서 enum에 대응하는 모든 분기(branch)를 커버해서 발생할 수 있는 경우의 수가 없지만 관습적으로 만들어주는 부분이다. 그래서 아래와 같이 default 레이블과 함께 도달할 수 없는 경우에도 예외를 발생시키는 등의 (상식적으로는) 이상한 sugar syntax를 넣어주곤 했다.

class TelecomFactory {
    public TelecomHandler create(Telecom telecom) {
        switch (telecom) {
            case KT:
                return new SktHandler();
            case SKT:
                return new KtHandler();
            default:
                throw new IllegalStateException();
        }
    }
}

 

 

위의 자바 코드를 Kotlin의 when으로 옮기면 아래와 같다.

class TelecomFactoryKt {
    fun create(telecom: Telecom): TelecomHandler {
        return when (telecom) {
            Telecom.KT -> SktHandler()
            Telecom.SKT -> KtHandler()
        }
    }
}

default 부분이 없어졌다. 굳이 default와 같은 것을 넣는다면 아래와 같이 else를 쓸 수는 있다.

class TelecomFactoryKt {
    fun create(telecom: Telecom): TelecomHandler {
        return when (telecom) {
            Telecom.KT -> SktHandler()
            Telecom.SKT -> KtHandler()
            else -> throw IllegalStateException()
        }
    }
}

하지만 해당 부분에 도달하지 않음을 IntelliJ IDEA는 알려준다.

'when' is exhaustive so 'else' is redundant here

만약 Telecom 이 nullable하다면 의미가 있기는 하다.

이제 진하다! 진해..

그렇다면?

어떻게 default를 없앨 수 있는 것일까?

IntelliJ IDEA의 바이트코드 생성기로 보면 TABLESWITCH 라는 JVM 명령어로 만들면서 default를 컴파일러가 알아서 끼워넣어줌을 알 수 있다. (L5 부분)

    TABLESWITCH
      1: L3
      2: L4
      default: L5

L5 부분을 보면 아래와 같이 되어 있다.

   L5
    NEW kotlin/NoWhenBranchMatchedException
    DUP
    INVOKESPECIAL kotlin/NoWhenBranchMatchedException.<init> ()V
    ATHROW

결국 자바코드로 코틀린 코드를 옮겨보면 NoWhenBranchMatchedException 예외를 던진다고 풀이할 수 있다.

class TelecomFactoryKt {
    fun create(telecom: Telecom): TelecomHandler {
        return when (telecom) {
            Telecom.KT -> SktHandler()
            Telecom.SKT -> KtHandler()
        }
    }
}

는 아래의 자바코드의 형태인 셈이다.

class TelecomFactory {
    public TelecomHandler create(Telecom telecom) {
        switch (telecom) {
            case KT:
                return new SktHandler();
            case SKT:
                return new KtHandler();
            default:
                throw new NoWhenBranchMatchedException();
        }
    }
}

조삼모사라고 할 수도 있지만 언어레벨이란 이런 것들이 많다. Generic도 컴파일되면 타입 소거가 되지 않는가..

'Languages' 카테고리의 다른 글

TL; DR 이란?  (0) 2018.10.04
[파이썬] cgi on IIS  (0) 2015.01.15
0.1+0.2? 부동소수점의 정밀도 문제...  (0) 2013.10.31