Name situations where SAM conversion does NOT apply, and explain how a Kotlin function type passed to Java differs from a SAM-converted lambda.
answer
- Interface only (abstract class excluded)
- Exactly one abstract method
- Java or fun interface, not plain Kotlin interface
- Function types compile to FunctionN.invoke
- fun interface = Java-friendly callbacks
basics
~20 sSAM conversion needs a Java interface with exactly one abstract method as the target. It won't fire for abstract classes, multi-method interfaces, plain Kotlin interfaces, or when the parameter is already a Kotlin function type. A function type passed to Java surfaces as a FunctionN object, not your interface.
solid answer
~50 sSAM conversion requires: (1) the target is an interface, not a class — even an abstract class with one method is excluded; (2) it has exactly one abstract method (default/static methods are fine); (3) for Kotlin interfaces, the fun interface modifier; and (4) you're actually passing a function value at that position. It also doesn't apply when the parameter's declared type is already a Kotlin function type ((T) -> R) — there's nothing to convert. If a Kotlin API takes a function type and you call it from Java, Kotlin exposes it as kotlin.jvm.functions.FunctionN (e.g. Function1) with an invoke method, so Java code must implement/instantiate that, not a friendly SAM interface. That's why libraries intended for Java consumers often declare a fun interface or a Java SAM type instead of a raw Kotlin function type.
code
kotlin · 8 lines// Java-consumer-friendly API uses a fun interface:
fun interface Transformer { fun transform(s: String): String }
fun process(t: Transformer): String = t.transform("in")
// From Java: process(s -> s.toUpperCase()); // clean single-method lambda
// Raw function type leaks Function1 to Java:
fun processFn(t: (String) -> String): String = t("in")
// From Java the param type is kotlin.jvm.functions.Function1<String,String>go deeper
Can state SAM needs a single-method Java interface and a lambda.
Lists the disqualifying cases (abstract class, multi-method, plain Kotlin interface).
Explains FunctionN compilation and the Java-consumer ergonomics difference between function types and fun interfaces.
Sets API conventions for cross-language libraries, weighing function types vs fun interfaces and the Unit.INSTANCE friction.
## Conditions required for SAM conversion All must hold: 1. **Target is an interface** — not a class. An abstract class with exactly one abstract method does **not** qualify. 2. **Exactly one abstract method.** Multiple abstract methods disqualify it. `default` and `static` methods (Java) don't count. 3. **Java interface, or a Kotlin `fun interface`.** A plain Kotlin interface is rejected. 4. **A function value is being supplied** (lambda or method reference) at that position. ## Cases where it does NOT apply ```kotlin // (a) Abstract class, not interface -> no SAM abstract class Task { abstract fun run() } // val t: Task = { } // ERROR // (b) Two abstract methods -> no SAM interface TwoOps { fun a(); fun b() } // (c) Plain Kotlin interface, no 'fun' -> no SAM interface Plain { fun go() } // (d) Parameter already a Kotlin function type -> nothing to convert fun apply(f: (Int) -> Int) = f(1) apply { it + 1 } // not SAM; this is a function type directly ``` ## Function type vs SAM interface across the JVM boundary A Kotlin function type `(T) -> R` is **not** a special language construct at the bytecode level — it compiles to one of the synthetic interfaces `kotlin.jvm.functions.FunctionN` (here `Function1<T, R>`) with a single `invoke` method. From **Kotlin**, you just write a lambda. But the difference shows when **Java** consumes the API: - If a Kotlin function declares a parameter of type `(Int) -> Int`, Java callers see a parameter of type `kotlin.jvm.functions.Function1<Integer, Integer>` and must implement its `invoke` method or build it via Java's own lambda machinery — and they return `Unit.INSTANCE` for `Unit`-returning ones. Awkward. - If instead the Kotlin API declares a **`fun interface`** or accepts a **Java SAM type**, the Java caller gets a clean single-method interface and can pass a Java lambda naturally. ```kotlin // Java-friendly: fun interface IntOp { fun apply(i: Int): Int } fun run(op: IntOp) = op.apply(10) // Java: run(i -> i + 1); // clean // Java-hostile-ish: fun runFn(op: (Int) -> Int) = op(10) // Java: runFn(i -> i + 1) works in modern Kotlin/Java but exposes Function1 ``` ## Practical guidance - For **Kotlin-only** APIs, prefer function types — they're idiomatic and need no conversion. - For **APIs meant to be called from Java**, prefer a `fun interface` (or a Java SAM type) so Java callers get clean lambdas and a documented method name. - Remember the `Unit` return quirk: function types returning `Unit` force Java callers to `return Unit.INSTANCE`. ## Summary SAM conversion is narrow: interface, single abstract method, Java-or-`fun`, supplying a function value. Outside those, you write an object expression, change the target type, or design the API with a `fun interface` for cross-language ergonomics.
- Does SAM conversion work for an abstract class with a single abstract method?No. SAM conversion is restricted to interfaces. An abstract class, even with one abstract method, requires an explicit object expression or subclass.
- How does a Java caller see a Kotlin parameter of type (Int) -> Unit?As kotlin.jvm.functions.Function1<Integer, Unit>; the lambda body must return Unit.INSTANCE, which is why fun interface is preferred for Java-facing APIs.
saying these in an interview costs you the question
- Thinking SAM conversion applies to abstract classes
- Believing a multi-abstract-method interface qualifies
- Not knowing function types compile to FunctionN interfaces
- Designing Java-facing Kotlin APIs with raw function types unaware of the Function1/Unit.INSTANCE friction