What is a SAM conversion in Kotlin, and how does it let you pass a lambda where a Java interface like Runnable or Comparator is expected?
answer
- SAM = Single Abstract Method
- Lambda -> anonymous interface instance
- Runnable, Comparator, Callable
- Java interfaces only by default
- Compile-time sugar, no reflection
basics
~20 sA SAM conversion lets you pass a short Kotlin lambda where Java expects an interface with exactly one method, like Runnable or Comparator. Kotlin turns the lambda into that interface automatically, so you skip the boilerplate anonymous class.
solid answer
~40 sSAM stands for Single Abstract Method. When a Java interface has exactly one abstract method (Runnable.run, Comparator.compare, Callable.call), Kotlin lets you pass a lambda directly instead of writing an anonymous object. The compiler wraps the lambda in an instance of that interface, mapping the lambda parameters to the method's parameters and its body to the method body. For example, Thread { println("hi") } passes a lambda where a Runnable is wanted, and listOf(3,1,2).sortedWith { a, b -> a - b } passes a Comparator. This only works for Java SAM interfaces by default; Kotlin's own interfaces need the fun interface modifier. The conversion is purely syntactic sugar over an anonymous implementation.
code
kotlin · 8 lines// Java expects a Runnable (one method: run)
val t = Thread { println("running") }
t.start()
// Java expects a Comparator<String> (one method: compare)
val names = listOf("bob", "al", "cy")
val byLength = names.sortedWith { a, b -> a.length - b.length }
println(byLength) // [al, cy, bob]go deeper
Knows SAM = single-abstract-method and can pass a lambda to Thread{} or sortedWith{}.
Explains the matching of lambda params to method params and that it's Java-interface-only by default.
Notes the generated anonymous class / invokedynamic and the fun interface boundary for Kotlin.
Frames SAM conversion as part of a deliberate interop ergonomics policy and its compile-time, zero-reflection guarantees.
## What SAM means **SAM = Single Abstract Method.** It refers to any interface that declares exactly one abstract (unimplemented) method. Classic Java examples: - `Runnable` — one method `void run()` - `Comparator<T>` — one method `int compare(T a, T b)` - `Callable<V>` — one method `V call()` ## The problem SAM conversion solves Without it, to satisfy a Java method that wants a `Runnable` you'd write a full anonymous implementation: ```kotlin Thread(object : Runnable { override fun run() { println("work") } }) ``` A **SAM conversion** lets the Kotlin compiler accept a lambda in that position and silently build the anonymous object for you: ```kotlin Thread { println("work") } // lambda becomes a Runnable ``` The lambda's parameters map onto the single method's parameters and the lambda body becomes the method body. For `Comparator<Int>`: ```kotlin val sorted = listOf(3, 1, 2).sortedWith { a, b -> a - b } // { a, b -> a - b } is converted to Comparator.compare(a, b) ``` ## Where it applies SAM conversion fires when: - The expected type is a **Java interface** with exactly one abstract method, AND - You supply a function value (a lambda or a `::method` reference) whose signature matches. It does **not** fire for Java *classes* (even abstract ones with a single method) — only interfaces. By default it also does **not** fire for **Kotlin** interfaces; you need the `fun interface` modifier for those (a separate feature called a *functional interface*). ## Mechanism, not magic The conversion is compile-time sugar. The generated bytecode is an anonymous class (or an `invokedynamic` lambda metafactory call) implementing the interface — the same thing you'd write by hand. There's no runtime reflection involved. ## Key takeaways - Saves boilerplate when calling Java APIs that take functional interfaces. - Only one abstract method allowed (default methods don't count against it). - Java interfaces work out of the box; Kotlin interfaces need `fun interface`.
- Does SAM conversion work for an interface with two abstract methods?No. There must be exactly one abstract method. Extra abstract methods disqualify it; default/static methods don't count.
- Can you pass a method reference instead of a lambda for a SAM conversion?Yes. A bound or unbound reference like ::doWork or obj::handle converts just like a lambda as long as its signature matches the single method.
It's like handing a one-line note where a form letter was expected — the system fills out the formal wrapper around your one line for you.
saying these in an interview costs you the question
- Thinking SAM conversion works for any class with one method (it's interfaces only)
- Believing it works automatically for Kotlin interfaces without fun interface
- Claiming it uses runtime reflection rather than compile-time sugar
- Confusing SAM (one abstract method) with 'any interface'