코틀린 언어 용어 사전
함수noinline · crossinline · reified

inline

함수 본문을 호출 지점에 펼쳐 람다 객체 생성을 없앤다. reified를 쓰려면 필수다.

함수 본문과 람다를 호출 지점에 그대로 펼쳐 넣는 것.

inline fun <T> measure(name: String, block: () -> T): T {
    val start = System.nanoTime()
    try { return block() }
    finally { Log.d("perf", "$name: ${System.nanoTime() - start}ns") }
}

measure("load") { repository.load() }
// 컴파일 후: 이 자리에 measure 의 본문과 람다가 통째로 펼쳐진다
// → 람다 객체가 생기지 않는다

무엇을 얻나

  • ① 람다 객체 생성 비용이 사라진다
  • ② 비지역 반환이 가능해진다 — 람다 안에서 바깥 함수를 return 할 수 있다
  • ③ reified 를 쓸 수 있다
fun find(users: List<User>): User? {
    users.forEach { if (it.isAdmin) return it }   // inline 이라 바깥 함수를 반환한다
    return null
}

표준 라이브러리의 forEach·let·apply가 전부 inline 이라 이런 코드가 자연스럽게 동작한다.

reified — 런타임에 타입을 안다

// ❌ 일반 제네릭 — 타입 소거로 T 를 알 수 없다
fun <T> parse(json: String): T = gson.fromJson(json, T::class.java)   // 컴파일 에러

// ✅ inline + reified — 호출 지점에 실제 타입이 박힌다
inline fun <reified T> parse(json: String): T = gson.fromJson(json, T::class.java)

val user: User = parse(jsonString)
// 안드로이드에서 자주 쓰는 형태
inline fun <reified T : Activity> Context.start() =
    startActivity(Intent(this, T::class.java))

context.start<DetailActivity>()

제어자

inline fun f(
    block: () -> Unit,
    noinline callback: () -> Unit,      // 이 람다는 인라인하지 않는다 (변수에 저장·반환할 때)
    crossinline handler: () -> Unit     // 인라인하되 비지역 반환은 금지 (다른 컨텍스트에서 실행될 때)
) { ... }
// crossinline 이 필요한 전형적 상황
inline fun runLater(crossinline block: () -> Unit) {
    Handler(Looper.getMainLooper()).post { block() }   // 나중에 다른 스택에서 실행된다
}

남용하면 오히려 손해

인라인은 코드를 '복사' 한다

  • 함수가 크고 여러 곳에서 부르면 바이트코드가 급격히 커진다
  • APK 크기 · 명령어 캐시 효율에 나쁘다

원칙: 람다를 인자로 받는 '작은' 함수에만 붙인다

  • 람다가 없는 함수에 inline 을 붙이면 컴파일러가 경고한다

면접 함정

  • "inline을 붙이면 빨라진다" → 람다 객체가 없어지는 것이지 로직이 빨라지지 않는다. 큰 함수면 오히려 손해다.
  • "reified만 붙이면 된다"inline이 함께 있어야 한다.

어디에 붙어 있나 — 표준 라이브러리

// 스코프 함수 · 컬렉션 연산 대부분이 inline 이다
public inline fun <T, R> T.let(block: (T) -> R): R
public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T>

// 그래서 이런 코드가 람다 객체를 만들지 않는다
list.filter { it > 0 }.map { it * 2 }

컴파일 결과를 확인하는 법

Android Studio → Tools → Kotlin → Show Kotlin Bytecode → Decompile

인라인된 함수는 호출 자리에 본문이 펼쳐져 있는 것을 볼 수 있다 람다가 객체로 남았는지, 사라졌는지도 확인된다

성능 착시 주의

  • "람다 = 객체 생성 = 느리다" 는 과장이다

  • 캡처가 없는 람다는 싱글턴으로 재사용된다

  • 젊은 세대 GC 는 짧게 사는 객체에 매우 싸다

  • 대부분의 안드로이드 코드에서 이 비용은 측정되지 않는다

정말 중요한 곳: 프레임마다 도는 코드 · 리스트 바인딩 · 애니메이션 루프 그 외에는 가독성을 우선한다

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 함수 심화 — 확장·고차·람다·inline·reified