How Kotlin implement lambda under the hood

yawei
2 min readOct 6, 2020

--

We know that in Android Java world, the lambda will be converted to anonymous class in the bytecode level. After Android start transferring into the Kotlin world, does Kotlin treat lambda expression the same way as Java? In this post, I will talk about how Kotlin implement and optimize lambda expression from a bytecode level. All the code based on Kotlin-1.4.10

How lambda implemented in bytecode level

First, let’s look at the following Kotlin lambda code snippet

code snippet for the lambda expression

the decompiled bytecode will be like

equivalent Java code for the lambda expression

when we use lambda in Kotlin, an inner static anonymous class will be created under the hood to replace the lambda. And as an optimization, instead of creating a new instance every time we invoke the lambda, the same single instance will be reused for every invocation.

In this example, we can see that the lambda is converted to an anonymous inner static class named MainActivity$onCreate$1.class, and the same instance has been reused across invocations

If the lambda captures variables from the surrounding scope, it’s no longer possible to reuse the same instance for every invocation, see the following snippet

lambda expression capturing the surrounding variable

the decompiled bytecode will be like

equivalent Java bytecode for the lambda expression capturing the surrounding variable

Instead, a new inner anonymous class instance will be created for every invocation. And the captured variable will be copied to the instance by constructor.

Passing SAM interface to a Java method

If you want to call a method defined in Java that accept a SAM (single abstract method) interface as parameter, you can pass in lambda

Pass in SAM Interface using lambda

or you can achieve the same effect by using object expression.

Pass in SAM Interface using object expression

So, what’s the difference? Let’s take a look at the bytecode. First, below is the decompiled bytecode for the lambda version

decompiled Java code for the lambda version

the lambda is converted to a static inner anonymous class implementing the SAM interface, and if the lambda doesn’t access any variables from surrounding scope, the same instance of the anonymous class is reused between calls.

Let’s examine the bytecode for the object expression version

we can see that when using object expression, a new instance implementing SAM interface is created on each invocation.

So, we should prefer using the lambda version to reduce the instance creation

Note: If the lambda captures variables from the surrounding scope, it’s no longer possible to reuse the same instance for every invocation

Summary

In Kotlin

  • If the lambda expression do not capture surrounding variable, the same anonymous class instance will be reused between calls
  • If the lambda captures surrounding variable, a new anonymous class instance will be created for every invocation
  • For passing SAM interface into Java method, prefer the lambda version to reduce instance creation

Thanks for reading!

--

--