(Kotlin/코틀린) when 표현식 심화 — subject 변수, 조건 결합
1. when 기본 복습
val x = 5
when (x) {
1 -> println("one")
2, 3 -> println("two or three")
else -> println("other")
}
when은 Java의 switch를 대체하지만 훨씬 강력합니다.
표현식으로도 사용 가능하여 값을 반환할 수 있습니다.
val result = when (x) {
1 -> "one"
2, 3 -> "two or three"
else -> "other"
}
2. subject 변수 선언 (Kotlin 1.7+)
when 괄호 안에서 변수를 직접 선언하고, 그 변수는 when 블록 안에서만 유효합니다.
// 기존 방식: 외부에 변수 선언
val result = getResult()
when (result) {
is Success -> handle(result)
is Error -> logError(result)
}
// result는 when 블록 밖에서도 접근 가능
// subject 변수: when 블록 스코프 안에만 존재
when (val result = getResult()) {
is Success -> handle(result)
is Error -> logError(result)
}
// result는 여기서 접근 불가 → 스코프 제한으로 코드 안전성 향상
실전 활용
when (val response = networkCall()) {
is ApiResponse.Success -> {
showData(response.data)
saveToCache(response.data)
}
is ApiResponse.Error -> showError(response.message)
is ApiResponse.Loading -> showLoading()
}
// 정규식 결과를 when 안에서 바로 사용
when (val match = regex.find(input)) {
null -> println("일치 없음")
else -> println("일치: ${match.value}")
}
3. 여러 조건 결합 (,)
쉼표로 여러 값을 하나의 브랜치에 묶을 수 있습니다.
enum class Day { MON, TUE, WED, THU, FRI, SAT, SUN }
fun isWeekend(day: Day) = when (day) {
Day.SAT, Day.SUN -> true
else -> false
}
fun getDayType(day: Day) = when (day) {
Day.MON, Day.TUE, Day.WED, Day.THU, Day.FRI -> "평일"
Day.SAT, Day.SUN -> "주말"
}
4. 범위 체크 (in, !in)
val score = 75
val grade = when (score) {
in 90..100 -> "A"
in 80..89 -> "B"
in 70..79 -> "C"
in 60..69 -> "D"
else -> "F"
}
println(grade) // C
// !in: 범위 밖
val isOutlier = when (value) {
!in 0..100 -> true
else -> false
}
// 컬렉션 포함 여부
val validCodes = setOf(200, 201, 204)
val message = when (statusCode) {
in validCodes -> "성공"
in 400..499 -> "클라이언트 오류"
in 500..599 -> "서버 오류"
else -> "알 수 없음"
}
5. 타입 체크 (is, !is)
fun describe(obj: Any): String = when (obj) {
is Int -> "정수: $obj"
is String -> "문자열 길이: ${obj.length}" // 스마트 캐스트 — obj가 String으로 자동 캐스팅
is List<*> -> "리스트 크기: ${obj.size}"
is Boolean -> if (obj) "참" else "거짓"
else -> "기타: ${obj::class.simpleName}"
}
describe(42) // "정수: 42"
describe("hello") // "문자열 길이: 5"
describe(true) // "참"
is 브랜치 안에서는 스마트 캐스트가 적용됩니다. 별도 캐스팅 불필요.
6. sealed class/interface 완전 분기
sealed 계층과 함께 사용하면 else를 생략하고 컴파일러가 누락된 브랜치를 검사합니다.
sealed interface Result<out T> {
data class Success<T>(val data: T) : Result<T>
data class Error(val exception: Exception) : Result<Nothing>
data object Loading : Result<Nothing>
}
fun <T> handleResult(result: Result<T>) = when (result) {
is Result.Success -> processData(result.data)
is Result.Error -> showError(result.exception.message)
is Result.Loading -> showLoading()
// else 불필요 — 컴파일러가 모든 케이스를 알고 있음
// 새 서브클래스 추가 시 컴파일 에러로 누락 방지
}
else를 넣으면 새 서브클래스 추가 시 누락되어도 컴파일이 통과합니다.
sealed 계층에서는 else 없이 모든 케이스를 명시하는 것이 안전합니다.
7. subject 없는 when — if-else 대체
when에 인자를 주지 않으면 각 브랜치가 Boolean 조건이 됩니다.
val x = 42
when {
x < 0 -> println("음수")
x == 0 -> println("영")
x < 100 -> println("양수 소수")
else -> println("100 이상")
}
// 복잡한 조건도 가독성 있게 표현
fun classify(user: User) = when {
user.age < 0 -> throw IllegalArgumentException("나이 오류")
user.age < 13 -> "어린이"
user.age < 18 -> "청소년"
user.age < 65 && user.isPremium -> "프리미엄 성인"
user.age < 65 -> "일반 성인"
else -> "시니어"
}
8. when 표현식으로 값 반환
when을 표현식으로 사용하면 변수에 할당하거나 함수 반환값으로 직접 사용합니다.
// 변수에 할당
val color = when (status) {
Status.OK -> Color.GREEN
Status.WARNING -> Color.YELLOW
Status.ERROR -> Color.RED
}
// 함수 반환값으로 직접 사용
fun statusColor(status: Status): Color = when (status) {
Status.OK -> Color.GREEN
Status.WARNING -> Color.YELLOW
Status.ERROR -> Color.RED
}
표현식으로 사용할 때는 else 브랜치가 반드시 있어야 합니다 (sealed 계층 제외).
9. Kotlin 2.0 — when의 guard 조건 (when with guards)
Kotlin 2.0에서 추가된 if 조건부 브랜치입니다.
// Kotlin 2.0+
when (value) {
is String if value.isNotEmpty() -> println("비어있지 않은 문자열: $value")
is String -> println("빈 문자열")
is Int if value > 0 -> println("양수: $value")
else -> println("기타")
}
기존에는 브랜치 내부에서 다시 if를 써야 했던 것을 브랜치 선언부에서 바로 조건을 추가할 수 있습니다.
// 기존 방식 (Kotlin 1.x)
when (value) {
is String -> {
if (value.isNotEmpty()) {
println("비어있지 않은 문자열")
} else {
println("빈 문자열")
}
}
}
// 새 방식 (Kotlin 2.0+)
when (value) {
is String if value.isNotEmpty() -> println("비어있지 않은 문자열")
is String -> println("빈 문자열")
}
10. 정리
| 기능 | 문법 | 주요 활용 |
|---|---|---|
| 기본 분기 | value -> |
상수/열거형 비교 |
| 여러 조건 결합 | v1, v2 -> |
동일 처리 그룹화 |
| 범위 체크 | in a..b -> |
점수, 상태코드 범위 |
| 타입 체크 | is Type -> |
다형성, 스마트 캐스트 |
| subject 변수 | when(val x = expr) |
스코프 제한 |
| subject 없는 when | when { cond -> } |
복잡한 조건 가독성 |
| sealed 완전 분기 | else 생략 |
누락 브랜치 컴파일 검사 |
| guard 조건 | is T if cond -> |
Kotlin 2.0+, 조건부 타입 분기 |
when을 적극적으로 활용하면 if-else if 체인보다 가독성이 높고, sealed 계층과 조합 시 컴파일러가 분기 누락을 검사해줍니다.