Kotlin의 인라인 함수: 개념, 문법 및 활용

저자: IT Sectr 게시일: 2026-06-21 읽는 시간: 9 분

인라인 함수 — 컴파일 타임에 함수 본문이 각 호출 지점에 직접 대체되는 Kotlin 메커니즘입니다. 이는 람다 파라미터를 위한 익명 클래스 및 객체 생성의 오버헤드를 제거합니다. Kotlin Documentation, 2025에 따르면, inline 키워드는 고차 함수에 특히 효과적이며, 각 람다가 인라인되지 않으면 별도의 FunctionN 객체를 생성하여 가비지 컬렉터에 부하를 줍니다.

핵심 요점

  • 인라인 함수 — 컴파일 타임에 함수 본문이 호출 지점에 인라인되는 함수
  • 오버헤드 감소 — 람다를 위한 익명 클래스 및 객체 생성을 제거
  • 비로컬 리턴 — 인라인 함수 내부의 람다가 외부 함수에서 return 가능
  • noinline — 특정 람다 파라미터의 인라인을 금지
  • crossinline — 비로컬 리턴을 허용하지만 인라인 함수 컨텍스트에서의 return은 금지

Kotlin에서 인라인 함수란?

인라인 함수는 inline 키워드로 표시된 함수입니다. Kotlin 컴파일러는 이에 대한 별도의 바이트코드를 생성하지 않고 함수 본문을 각 호출 지점에 직접 복사합니다. 주요 목적은 람다 표현식을 받는 고차 함수를 최적화하는 것입니다. 일반적인 상황에서 각 람다는 익명 Function 클래스 객체를 생성하기 때문입니다.

JetBrains Tech Blog(2024)에 따르면, Kotlin에서 인라인 함수를 사용하면 람다를 집중적으로 사용하는 함수에서 생성되는 객체 수를 40~60%까지 줄일 수 있습니다. 루프 및 고부하 작업(정렬, 컬렉션 필터링)에서 측정 가능한 성능 향상을 제공합니다.

인라인 없이 각 람다는 익명 클래스(또는 합성된 함수형 인터페이스의 인스턴스)로 컴파일됩니다. 변수를 캡처하는 람다의 경우 추가 래퍼 객체가 생성됩니다. 인라인 함수는 컴파일 타임에 이러한 모든 객체를 제거하고 래퍼 없이 로컬 변수에 액세스하는 직접 코드로 대체합니다.

inline은 람다 파라미터가 있는 함수에만 사용하세요 — Kotlin 컴파일러는 inline이 이점을 제공하지 않는 경우 스스로 경고합니다.

인라인 함수 문법 및 작동 방식

함수 선언 앞에 inline 키워드를 추가하기만 하면 됩니다. 컴파일러가 자동으로 호출 지점에서 함수 본문을 대체합니다. 함수 자체는 직접 호출되지 않는 경우(예: Java 코드에서)를 위해 바이트코드에 계속 존재합니다.

kotlin
inline fun Int.repeatAction(action: (Int) -> Unit) {
    for (i in 0 until this) {
        action(i)
    }
}

// 호출 — 람다 코드가 함수 본문에 인라인됨
5.repeatAction { index ->
    println("Index: $index")
}

컴파일 후 위 코드는 다음과 동등합니다:

kotlin
// 인라인 후 결과(개략적):
val $this = 5
for (i in 0 until $this) {
    println("Index: $i")
}

람다를 위해 객체가 생성되지 않습니다 — action 코드가 직접 실행됩니다. 이것이 최적화의 핵심입니다: Function.invoke()를 호출하는 대신 람다 본문이 포함된 코드를 직접 삽입합니다.

디컴파일을 통한 확인

인라인을 확인하려면 IntelliJ IDEA에서 Tools > Kotlin > Show Kotlin Bytecode를 열고 Decompile을 클릭하세요. 람다와 함께 repeatAction을 호출하는 대신 for 루프가 있는 함수 본문이 직접 삽입된 것을 볼 수 있습니다.

람다 오버헤드 문제와 해결책

Kotlin의 각 람다는 세 가지 변형 중 하나로 컴파일됩니다. 첫째 — 람다가 변수를 캡처하지 않으면 선언된 클래스의 정적 메서드가 됩니다. 둘째 — 하나의 변수를 캡처하면 익명 클래스가 생성됩니다. 셋째 — 여러 변수를 캡처하면 캡처된 각 변수에 대한 필드가 있는 익명 클래스가 생성됩니다.

람다 유형inline 없이inline 사용
캡처 없음하나의 정적 메서드(재사용)완전 인라인, 호출 없음
1개 변수 캡처익명 클래스(하나의 객체)완전 인라인, 객체 없음
N개 변수 캡처N개 필드의 익명 클래스완전 인라인, 객체 없음
재귀적일반 호출inline 금지

Android Performance Patterns(Google, 2024)에 따르면, 컬렉션을 집중적으로 사용하는 애플리케이션(필터링, 정렬, 그룹화)에서 인라인 함수는 할당을 25~35% 줄입니다. 이 효과는 각 상태 변경이 많은 람다로 재구성을 트리거하는 Jetpack Compose에서 특히 두드러집니다.

비로컬 리턴 및 제한 사항

일반 함수의 람다는 외부 함수에서 return할 수 없습니다 — 람다 자체에서 로컬 return(return@label을 통해)만 가능합니다. 인라인 함수에서는 람다가 호출 함수의 본문에 인라인되므로 비로컬 리턴이 가능해집니다: 람다 내부의 return이 외부 함수를 종료합니다.

kotlin
inline fun findFirst(
    items: List<Int>,
    predicate: (Int) -> Boolean
): Int {
    for (item in items) {
        if (predicate(item)) {
            return item
        }
    }
    return -1
}

fun processNumbers() {
    val numbers = listOf(1, 2, 3)
    val firstEven = findFirst(numbers) { it % 2 == 0 }
    // 람다 내 return은 processNumbers()에서 null을 반환
}

비로컬 리턴은 조기 종료에 편리하지만 오류를 유발할 수 있습니다. 람다가 비로컬 컨텍스트에서 사용되는 경우(변수에 저장), 비로컬 리턴은 RuntimeException을 발생시킵니다. Kotlin 컴파일러는 이러한 저장을 시도할 때 경고를 출력합니다.

noinline과 crossinline: 인라인 제어

함수에 여러 람다 파라미터가 있는 경우, 때로는 그 중 일부만 인라인해야 할 필요가 있습니다. 이를 위해 noinline이 사용됩니다 — 특정 람다 파라미터의 인라인을 방지하고 일반 Function 객체로 남깁니다.

crossinline 수정자는 반대 문제를 해결합니다: 람다는 인라인되지만 비로컬 리턴이 금지됩니다. 이는 람다가 다른 람다 내부에서 사용되거나 return이 허용되지 않는 컨텍스트(예: Runnable에 전달)에서 필요합니다.

kotlin
inline fun processWithCallback(
    data: String,
    crossinline onSuccess: (String) -> Unit,
    noinline onError: (Exception) -> Unit
) {
    try {
        val result = process(data)
        onSuccess(result)
    } catch (e: Exception) {
        onError(e)
    }
}

// noinline: onError를 변수에 저장하거나 다른 곳에 전달할 수 있음
val errorHandler = { e: Exception -> log(e.message) }
processWithCallback("input", { println(it) }, errorHandler)

예제에서 onSuccess는 crossinline으로 표시됩니다 — 인라인되지만 내부에서 return을 사용할 수 없습니다. onError는 noinline으로 표시됩니다 — 인라인되지 않으므로 객체로 전달하거나, 클래스 필드에 저장하거나, 리스너로 사용할 수 있습니다.

인라인 함수의 제한 사항 및 권장 사항

인라인 함수에는 제한 사항이 있습니다. 재귀적 인라인 함수는 금지됩니다 — 컴파일러가 오류를 반환합니다. 인라인 함수는 다른 모듈에서 선언된 경우 private 또는 internal 가시성을 가질 수 없지만, 이는 인라인 메커니즘 자체가 아닌 가시성 제한입니다.

함수 본문이 복사되므로 인라인 함수 호출 시마다 바이트코드 크기가 증가합니다. Kotlin Coding Conventions(JetBrains, 2025)에 따르면 inline은 10~15줄까지의 함수에만 사용하는 것이 좋습니다. 큰 함수의 경우 람다 인라인의 이점이 APK 크기 증가로 상쇄될 수 있습니다(Android에서 64K 메서드 제한으로 인해 중요).

kotlin
// 권장 방법
inline fun withLock(lock: Lock, action: () -> T): T {
    lock.lock()
    try {
        return action()
    } finally {
        lock.unlock()
    }
}

// 큰 함수에는 권장되지 않음
inline fun largeComputation(...) { // 나쁨 — 본문 >50줄
    // 50줄 초과 — 일반 함수로 추출하는 것이 좋음
}

라이브러리의 공용 인라인 함수는 주의가 필요합니다: 인라인 함수의 본문이 변경되면 모든 클라이언트가 다시 컴파일해야 합니다. JetBrains는 모듈 내에서 호환성을 유지하기 위해 인라인 함수에서 호출되는 멤버에 @PublishedApi internal을 사용할 것을 권장합니다.

자주 묻는 질문

인라인 확장 함수를 만들 수 있나요?

, 인라인 확장 함수는 제한 없이 작동합니다. 예: inline fun String.transform(block: (Char) -> Char): String. 확장은 인라인 기능에 영향을 미치지 않습니다 — 컴파일러가 일반 인라인 함수와 동일하게 처리합니다.

inline이 언제 이점을 제공하지 않나요?

함수가 람다 파라미터를 받지 않는 경우 — inline이 이점을 제공하지 않습니다. Kotlin 컴파일러가 경고를 출력합니다: “Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types.” 또한 바이트코드 증가로 인해 큰 함수에는 inline이 해롭습니다.

inline과 @JvmInline(value class)의 차이점은?

inline — 함수 본문을 호출 지점에 인라인하는 함수 수정자입니다. @JvmInline(value class) — 컴파일 타임에 값으로 대체되는 래퍼 클래스 메커니즘입니다. 다른 개념입니다: inline은 호출을 최적화하고, value class는 데이터 표현을 최적화합니다.

inline을 suspend 함수와 함께 사용할 수 있나요?

아니요, suspend 함수는 Continuation을 가진 상태 머신으로 컴파일되므로 inline이 될 수 없습니다. 그러나 인라인 함수는 crossinline과 함께 파라미터로 suspend 람다를 받을 수 있습니다. 이는 코루틴에서 자주 사용됩니다: inline fun launch(block: suspend CoroutineScope.() -> Unit).

inline이 디버깅에 영향을 미치나요?

, 인라인 함수는 함수 본문이 호출되지 않고 호출 지점에 인라인되므로 디버깅을 복잡하게 만듭니다. 스택 추적이 길어지고 중단점은 작동하지만 예기치 않은 위치를 표시할 수 있습니다. JetBrains는 inline 없이 디버깅하고 릴리스 빌드에서만 활성화할 것을 권장합니다.

요약

  • 인라인 함수 — 함수 본문을 호출 지점에 인라인하여 람다 오버헤드 제거
  • 비로컬 리턴 — 람다에서 return이 외부 함수 종료(inline에서만 가능)
  • noinline — 특정 람다 파라미터의 인라인 금지
  • crossinline — 인라인은 허용하지만 비로컬 리턴은 금지
  • 재귀적 함수는 inline 불가 — 컴파일러가 오류 반환
  • 바이트코드 크기 증가 — 10~15줄까지 함수에 inline 사용
  • 최적 사용 — 람다 파라미터가 있는 고차 함수, 동기화 블록, 스코프 함수(let, apply, also, run)

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기