If I can use if, when to use when

DoDoBest

·

2024. 3. 6. 12:57

Kotlin 공식문서에서도 if 대신 when을 사용할 것을 권장하고 있습니다.

그런데 왜 if 대신 when을 사용해야 하는지 아시나요?

Prefer using when if there are three or more options.

https://kotlinlang.org/docs/coding-conventions.html#if-versus-when

 

Coding conventions | Kotlin

 

kotlinlang.org

 

 

Kotlin의 when은 Java의 switch 문으로 변환된다.

Kotlin에서 when을 사용하는 코드는 Java의 switch 문으로 변환됩니다. 직접 확인해봅시다.

 

아래와 같이 사용자가 입력한 값에 따라 Grade를 반환하는 함수가 있습니다.

enum class Grade {
    FirstFreshman, FirstSophomore, FirstJunior, FirstSenior,
    SecondFreshman, SecondSophomore, SecondJunior, SecondSenior,
}

fun checkWithWhen(age: Int): Grade {
    return when (age) {
        90 -> Grade.FirstSenior
        80 -> Grade.FirstJunior
        70 -> Grade.FirstSophomore
        60 -> Grade.FirstFreshman
        50 -> Grade.SecondSenior
        40 -> Grade.SecondJunior
        30 -> Grade.SecondSophomore
        else -> Grade.SecondFreshman
    }
}

 

Kotlin Bytecode를 Java로 디컴파일된 코드를 살펴보면, switch 문으로 바뀐 것을 확인할 수 있습니다.

Switch 문의 특징

컴파일러가 switch 문을 컴파일 할 때, 각 case의 constant를 확인한 후, Jump Table을 생성합니다.
Jump Table은 case에 해당하는 값을 Key, case에 해당하는 코드가 존재하는 메모리 주솟값을 value로 가지는 Map입니다. 만약 1,2,3,4,5와 같이 Case가 붙어 있는 경우 List로 생성하기도 합니다.

 

If-else 문은 조건식을 모두 비교하기에 O(n)이 걸립니다.

switch 문은 jumpTable[caseNum]과 같이 실행해야 하는 코드를 바로 알 수 있기에 O(1)이 걸립니다.

 

https://thuc.space/posts/jump_table/

Switch 문은 if-else보다 얼마나 빠를까?

if-else 문과 when 문으로 실행한 후 걸리는 시간을 측정해서 비교해봤습니다.

 

10,000,000,000번 반복한 결과

if-else : 2243, 2250, 2242, 2197
when : 2236, 2228, 2230, 2191

 

100,000,000,000번 반복한 결과

if-else : 22237, 22357, 22464, 22001

when : 21873, 21803, 21803, 22279

enum class Grade {
    FirstFreshman, FirstSophomore, FirstJunior, FirstSenior,
    SecondFreshman, SecondSophomore, SecondJunior, SecondSenior,
}

fun main() {
    val age = 40

    val st = System.currentTimeMillis()
    for (i in 0 until 10_000_000_000) {
        checkWithIf(age)
    }
    val timeOfIf = System.currentTimeMillis() - st

    val st2 = System.currentTimeMillis()
    for (i in 0 until 10_000_000_000) {
        checkWithWhen(age)
    }
    val timeOfWhen = System.currentTimeMillis() - st2

    println("If 소요 시간: $timeOfIf") // 2243, 2250, 2242, 2197
    println("When 소요 시간: $timeOfWhen") // 2236, 2228, 2230, 2191
}

fun checkWithIf(age: Int): Grade {
    return if (age == 90) {
        Grade.FirstSenior
    } else if (age == 80) {
        Grade.FirstJunior
    } else if (age == 70) {
        Grade.FirstSophomore
    } else if (age == 60) {
        Grade.FirstFreshman
    } else if (age == 50) {
        Grade.SecondSenior
    } else if (age == 40) {
        Grade.SecondJunior
    } else if (age == 30) {
        Grade.SecondSophomore
    } else {
        Grade.SecondFreshman
    }
}

fun checkWithWhen(age: Int): Grade {
    return when (age) {
        90 -> Grade.FirstSenior
        80 -> Grade.FirstJunior
        70 -> Grade.FirstSophomore
        60 -> Grade.FirstFreshman
        50 -> Grade.SecondSenior
        40 -> Grade.SecondJunior
        30 -> Grade.SecondSophomore
        else -> Grade.SecondFreshman
    }
}

 

When의 또다른 장점

when은 exhaustive하다는 특징이 있습니다. if 문은 else문에 도달하지 않는 것이 분명함에도 else가 강제되는 경우가 있습니다.

반면 when은 enum, sealed를 이용할 경우 else를 붙이지 않아도 됩니다.

enum class LastName {
    Kim, Lee
}

fun main() {
    val lastName = LastName.Kim

    generateNameWithIf(lastName)
    generateNameWithWhen(lastName)
}

fun generateNameWithIf(lastNam: LastName): String {
    return if (lastNam == LastName.Lee) {
        "이민수"
    } else if (lastNam == LastName.Kim) {
        "김민수"
    } else { // else block이 필수
        "미지정"
    }
}

fun generateNameWithWhen(lastNam: LastName): String {
    return when (lastNam) {
        LastName.Lee -> "이민수"
        LastName.Kim -> "김민수"
    }
}

 

다음과 같이 조건식에 모든 경우를 포함하더라도, when 절은 else 구문을 강제합니다.

when 절에서 else 구문을 없애려면 sealed, enum을 활용해야 함을 알 수 있습니다.

 

fun getGrade(age: Int): String {
    return when(age) { // 'when' expression must be exhaustive, add necessary 'else' branch
        in Int.MIN_VALUE until 0 -> "Bad"
        in 0 until 30 -> "Good"
        in 30 .. Int.MAX_VALUE -> "Excellent"
    }
}

 

 

 

참고자료

https://www.geeksforgeeks.org/switch-vs-else/

 

switch vs if else - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

https://thuc.space/posts/jump_table/

 

Thuc notes - Jump table (branch table)

The jump table is a method to transfer program control to another code block using a table of branch or jump instructions.

thuc.space

https://www.reddit.com/r/C_Programming/comments/195sn4c/how_does_the_compiler_construct_a_jump_table_map/

 

From the C_Programming community on Reddit

Explore this post and more from the C_Programming community

www.reddit.com

 

'학습 > CS' 카테고리의 다른 글

Sealed class vs Sealed interface vs Enum  (0) 2024.03.05
Kotlin에서 data class는 왜 사용할까  (0) 2024.02.16