Skip to content

Kotlin Inline Functions

🧩 1. Background: Why Do We Need Inline Functions?

In Kotlin, higher-order functions are very common, for example:

kotlin
fun repeatAction(action: () -> Unit) {
    for (i in 1..3) {
        action()
    }
}

And you might call it like this:

kotlin
repeatAction {
    println("Hello")
}

👉 The problem is: Every time repeatAction is called, Kotlin must create a function object (Lambda instance) and invoke it at runtime. These operations:

  • Allocate heap memory (for the Lambda object)
  • Increase the call stack (reducing performance)

For small or frequently invoked functions, this overhead can be significant.


⚙️ 2. How Inline Functions Work (Key Concept)

When you mark a function with inline:

kotlin
inline fun repeatAction(action: () -> Unit) {
    for (i in 1..3) {
        action()
    }
}

The compiler does this at compile time:

It copies the function body directly into the call site. 🚫 No extra function object or call stack is created.

So the generated code effectively looks like:

kotlin
// The compiler-generated result is roughly:
for (i in 1..3) {
    println("Hello")
}

In other words, the function call is “expanded”.


⚡ 3. Benefits of Inlining

BenefitDescription
🚀 Better performanceAvoids Lambda object creation and function call overhead
💡 Supports non-local return (return)Allows returning directly from the outer function inside a Lambda
🧱 Compile-time expansionNo runtime cost

🚫 4. But There Are Trade-offs!

DrawbackDescription
📦 Larger bytecode (code bloat)Too much inlining increases code size
⚠️ Not suitable for large functionsOnly ideal for small, frequently used functions
💭 Harder to debugStack traces may look “skipped” after inlining

🔒 5. noinline and crossinline

In an inline function, you can control how each Lambda parameter behaves.

🔸 noinline — Do Not Inline This Parameter

kotlin
inline fun runTwo(action1: () -> Unit, noinline action2: () -> Unit) {
    action1() // inlined
    action2() // not inlined, object is created
}

Used when you need to keep a Lambda as an object (e.g., to pass it to another function).


🔸 crossinline — Disallow Non-local Returns

kotlin
inline fun runCross(crossinline action: () -> Unit) {
    Thread { action() }.start()
}

Because action runs on another thread, it cannot directly return from the outer function.


🧠 6. Common Use Cases for inline

ScenarioExampleDescription
Higher-order functions (e.g., collection ops)list.forEach { ... }Widely used in Kotlin standard library
DSL syntaxapply, run, with, also, letReduces object creation and call layers
Small repetitive logicmeasureTimeMillis { ... }Avoids Lambda call overhead

🔍 7. Summary at the Bytecode Level

AspectRegular FunctionInline Function
Call mechanismRuntime callCompile-time expansion
LambdaCreates an objectCode is inlined, no object
PerformanceSlower (some overhead)Faster (no call stack)
Best forAny use caseSmall, frequent, higher-order functions

✅ 8. In Short

Kotlin inline functions

  • Expand the function body at compile time
  • Reduce Lambda invocation and allocation overhead
  • Support non-local returns
  • Should be avoided for large functions to prevent code bloat

❓ How Java Calls Inline Functions

You're absolutely right — the behavior you observed is typical: Kotlin inline functions often cannot be called directly from Java, and here’s why 👇


1️⃣ The Nature of Kotlin Inline Functions

An inline function in Kotlin is a compile-time concept, meaning:

  • The compiler inserts the function body at the call site in Kotlin code.
  • Therefore, there might be no actual method generated in the JVM bytecode (especially for inline functions with Lambda parameters).

2️⃣ When Java Can or Cannot Call Inline Functions

SituationCompiled BehaviorCallable from Java
Normal inline function (no Lambda params)May generate a static method but usually inlined✅ Yes (if method exists)
Inline higher-order function (with Lambda params)Inlined Lambdas, no standalone method generated❌ No (method signature not found)
Inline + @JvmName / @JvmStaticCan force a static method to be generated✅ Yes, if explicitly named

⚠️ In short: Inline functions exist for Kotlin compile-time expansion, so the JVM might not have an actual callable method for Java.


3️⃣ Solutions

If you want Java to be able to call it:

Method 1: Remove inline

kotlin
fun greet(name: String) {
    println("Hello, $name")
}

This generates a regular JVM method callable from Java.


Method 2: Use @JvmName or @JvmStatic

kotlin
class Utils {
    companion object {
        @JvmStatic
        inline fun greet(name: String) {
            println("Hello, $name")
        }
    }
}

Java call:

java
Utils.greet("Alice");

⚠️ Note: If the function has Lambda parameters, even @JvmStatic won’t help — Java can’t pass Kotlin Lambdas directly; you’d need a Java functional interface.


Method 3: Provide a Java-friendly Wrapper

kotlin
inline fun greetInline(name: String) { println("Hello, $name") }

// Java-compatible wrapper
fun greetForJava(name: String) = greetInline(name)

4️⃣ Summary of the Reasoning

  • Kotlin inline functions are compile-time constructs, not guaranteed to generate JVM methods.
  • Inline higher-order functions (with Lambdas) are fully expanded during compilation, so Java finds no method to call.
  • For Java to call Kotlin functions, there must be a real JVM-level method.

Just something casual. Hope you like it.