코틀린의 when은 자바의 switch를 대치하되 훨씬 더 강력하다.
2.3.1 enum 클래스 정의
enum class Color {
RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET
}
코틀린에서 enum은 소프트 키워드다.
소프트 키워드(soft keyweord)란?
소프트 키워드는 특정 상황에서는 키워드로 작동하지만, 다른 문맥에서는 일반 식발자로 사용할 수 있는 단어. 예를 들어, enum은 함수나 변수명으로 사용할 수 있다. (when, class는 안된다)
코틀린의 소프트 키워드 목록: by, file, catch, finally, constructor, set, get, init, where
자바와 마찬가지로 enum은 단순히 값만 열거하는 존재가 아니다. enum 클래스 안에도 프로퍼티나 메소드를 정의할 수 있다.
enum class Color(
val r: Int, val g: Int, val b: Int
) {
RED(255, 0, 0), ORANGE(255, 165, 0),
YELLOW(255, 255, 0), GREEN(0, 255, 0), BLUE(0, 0, 255);
fun rgb() = (r * 256 + g) * 256 + b // enum 클래스 안에서 메소드 정의
}
>>> println(Color.BLUE.rgb())
255
2.3.2 when으로 enum 클래스 다루기
무지개의 색을 기억하기 위한 연상법을 적용한 문장의 예로는, "Richard Of York Gave Battle In Vain"을 들 수 있다. 이를 코틀린의 when을 이용해 함수를 만들어보자.
fun getMnemonic(color: Color) = // 식을 본문으로 하는 함수
when (color) {
Color.RED -> "Richard"
Color.ORANGE -> "Of"
Color.YELLOW -> "York"
Color.GREEN -> "Gave"
Color.BLUE -> "Battle"
Color.INDIGO -> "In"
Color.VIOLET -> "Vain"
}
>>> println(getMnemonic(Color.BLUE))
Battle
자바와 달리 각 분기의 끝에 break를 넣지 않아도 된다.
한 분기 안에서 여러 값을 매치 패턴으로 사용할 수도 있다.
fun getWarmth(color: Color) = when (color) {
Color.RED, Color.ORANGE, Color.YELLOW -> "warm"
Color.GREEN -> "neutral"
Color.BLUE, Color.INDIGO, Color.VIOLET -> "cold"
}
>>> println(getWarmth(Color.GREEN))
warm
2.3.3 when과 임의의 객체를 함께 사용
코틀린의 when은 자바의 switch보다 훨씬 더 강력하다. 자바 switch와 달리 코틀린 when의 분기 조건은 임의의 객체를 허용한다.
fun mix(c1: Color, c2: Color) =
when (setOf(c1, c2)) {
setOf(RED, YELLOW) -> ORANGE
setOf(YELLOW, BLUE) -> GREEN
setOf(BLUE, VIOLET) -> INDIGO
else -> throw Exception("Dirty Color")
}
>>> println(mix(BLUE, YELLOW))
GREEN
when의 분기 조건 부분에 식을 넣을 수 있기 때문에 많은 경우 코드를 더 간결하고 아름답게 작성할 수 있다.
2.3.4 인자 없는 when 사용
사실 2.3.3의 예제는 약간 비효율적이다. 이 함수는 호출될 때마다 함수 인자로 주어진 두 색이 when의 분기 조건에 있는 다른 두 색과 같은지 비교하기 위해 여러 Set 인스턴스를 생성한다.
인자가 없는 when 식을 사용하면 불필요한 객체 생성을 막을 수 있다. 이 경우 코드의 가독성이 약간 떨어지지만, 성능을 더 향상시킬 수 있다.
fun mixOptimized(c1: Color, c2: Color) =
when {
(c1 == RED && c2 == YELLOW) ||
(c1 == YELLOW && c2 == RED) ->
ORANGE
(c1 == YELLOW && c2 == BLUE) ||
(c1 == BLUE && c2 == YELLOW) ->
GREEN
(c1 == BLUE && c2 == VIOLET) ||
(c1 == VIOLET && c2 == BLUE) ->
INDIGO
else -> throw Exception("Dirty Color")
}
>>> println(mixOptimized(BLUE, YELLOW))
GREEN
2.3.5 스마트 캐스트: 타입 검사와 타입 캐스트를 조합
interface Expr
class Num(val value: Int) : Expr // Expr 인터페이스를 구현한다
class Sum(val left: Expr, val right: Expr) : Expr
자바 스타일의 if문 활용 타입 검사
fun eval(e: Expr): Int {
if (e is Num) {
val n = e as Num
return n.value
}
if (e is Sum) {
return eval(e.right) + eval(e.left)
}
throw IllegalArgumentException("Unknown expression")
}
>>> println(eval(Sum(Sum(Num(1), Num(2)), Num(4))))
7
코틀린에서는 is를 사용해 변수 타입을 검사한다. is 검사는 자바의 instanceof와 비슷하다. 하지만 자바에서 어떤 변수의 타입을 instanceof로 확인한 다음에 그 타입에 속한 멤버에 접근하기 위해서는 명시적으로 변수 타입을 캐스팅해야 한다.
코틀린에서는 컴파일러가 대신 캐스팅을 해준다. 어떤 변수가 원하는 타입인지 일단 is로 검사하고 나면 굳이 변수를 원하는 타입으로 캐스팅하지 않아도 마치 처음부터 그 변수가 원하는 타입으로 선언된 것처럼 사용할 수 있다. 이를 스마트 캐스트라고 부른다.
원하는 타입으로 명시적으로 타입 캐스팅하려면 as 키워드를 사용할 수 있다.
val n = e as Num
객체가 타입 변환이 가능하지 않은 타입이라면 ClassCastException이 발생한다. 이런 경우를 예방하기 위해 as? 연산자를 사용할 수 있다.
val n = e as? Num // e를 Num 타입으로 변경할 수 없다면 null이 반환된다.
2.3.6 리팩토링: if를 when으로 변경
if의 분기에 식이 하나밖에 없다면 중괄호를 생략해도 된다. if 분기에 블록을 사용하는 경우 그 블록의 마지막 식이 그 분기의 결과 값이다. 이 경우 when을 사용해 더 다듬을 수도 있다.
fun eval(e: Expr): Int =
when (e) {
is Num ->
e.value
is Sum ->
eval(e.right) + eval(e.left)
else ->
throw IllegalArgumentException("Unknown expression")
}
if 예제와 마찬가지로 when 사용시에도 타입을 검사하고 나면 스마트 캐스트가 이뤄진다.
2.3.7 if와 when의 분기에서 블록 사용
if나 when 모두 분기에 블록을 사용할 수 있다. 그런 경우 블록의 마지막 문장이 블록 전체의 결과가 된다(return이 필요없다).
fun evalWithLogging(e: Expr): Int =
when (e) {
is Num -> {
println("num: ${e.value}")
e.value
}
is Sum -> {
val left = evalWithLogging(e.left)
val right = evalWithLogging(e.right)
println("sum: $left + $right")
left + right
}
else -> throw IllegalArgumentException("Unknown expression")
}
'블록의 마지막 식이 블록의 결과'라는 규칙은 블록이 값을 만들어내야 하는 경우 항상 성립한다.
하지만 이 규칙은 블록이 본문인 함수에는 적용되지 않아, 블록이 본문인 함수는 내부에 return문이 반드시 있어야 한다.
'Kotlin' 카테고리의 다른 글
[Kotlin in Action] 2.5 코틀린 예외 처리 (0) | 2025.03.14 |
---|---|
[Kotlin in Action] 2.4 대상을 이터레이션: while과 for 루프 (0) | 2025.03.14 |
[Kotlin in Action] 2.2 클래스와 프로퍼티 (0) | 2025.03.14 |
[Kotlin in Action] 2.1 기본 요소: 함수와 변수 (0) | 2025.03.14 |
[Kotlin in Action] 1.5 코틀린 도구 사용 (0) | 2025.03.14 |
댓글