(Kotlin/코틀린) Nullable receiver 확장함수 완전 정리


1. Nullable receiver 확장함수란?

수신 타입에 ?를 붙여 null인 객체에도 안전하게 호출할 수 있는 확장함수입니다.

fun String?.orDefault(default: String = ""): String = this ?: default

val name: String? = null
println(name.orDefault("이름 없음"))  // 이름 없음
println("Alice".orDefault())          // Alice

null 체크 없이 호출할 수 있어 null 처리 코드가 간결해집니다.


2. 표준 라이브러리의 nullable receiver 예시

Kotlin 표준 라이브러리도 이 패턴을 많이 사용합니다.

// isNullOrEmpty, isNullOrBlank
val s: String? = null
println(s.isNullOrEmpty())   // true
println(s.isNullOrBlank())   // true

// toString()은 Any?에 정의되어 null에도 호출 가능
val obj: Any? = null
println(obj.toString())  // "null"

3. 내부에서 null 처리

함수 내부에서 this가 null일 때의 동작을 명시적으로 정의합니다.

fun List<*>?.safeSize(): Int = this?.size ?: 0

val list: List<Int>? = null
println(list.safeSize())       // 0
println(listOf(1, 2, 3).safeSize())  // 3
fun Any?.isNull(): Boolean = this == null
fun Any?.isNotNull(): Boolean = this != null

val x: String? = "hello"
if (x.isNotNull()) println("값 있음")

4. 실전 패턴 — Android View 확장

fun View?.show() { this?.visibility = View.VISIBLE }
fun View?.hide() { this?.visibility = View.GONE }
fun View?.invisible() { this?.visibility = View.INVISIBLE }

// null이어도 안전하게 호출
binding?.progressBar.show()
binding?.errorView.hide()
// 클릭 리스너도 nullable receiver로
fun View?.onClick(action: () -> Unit) {
    this?.setOnClickListener { action() }
}

button?.onClick { viewModel.submit() }

5. 실전 패턴 — 컬렉션 유틸

fun <T> Collection<T>?.orEmpty(): List<T> = this?.toList() ?: emptyList()
// 표준 라이브러리에 이미 있지만, 확장 패턴 이해용

fun <T> List<T>?.firstOrDefault(default: T): T = this?.firstOrNull() ?: default
fun <T> List<T>?.lastOrDefault(default: T): T = this?.lastOrNull() ?: default

val items: List<String>? = null
println(items.firstOrDefault("없음"))  // 없음
println(listOf("a", "b").firstOrDefault("없음"))  // a

6. 일반 확장함수 vs nullable receiver 비교

// 일반 확장함수: null이면 NPE
fun String.shout() = toUpperCase() + "!"
val s: String? = "hello"
// s.shout()  // 컴파일 에러: String?에 String 확장함수 호출 불가
s?.shout()   // 안전 호출 연산자 사용 필요

// nullable receiver: null 포함 바로 호출 가능
fun String?.shoutSafe() = (this ?: "").uppercase() + "!"
s.shoutSafe()   // HELLO! — 안전 호출 없이도 가능
null.shoutSafe() // !

7. 주의 사항

// this가 null일 때 처리를 잊으면 NPE 발생 가능
fun String?.badExtension(): Int = length  // ⚠️ this가 null이면 NPE

// 올바른 패턴
fun String?.safeLength(): Int = this?.length ?: 0

nullable receiver는 편리하지만 내부에서 this를 사용할 때는 반드시 null 체크(?. 또는 ?: )가 필요합니다.


8. 정리



Related Posts