Effective Kotlin: Item 6 — Avoid creating unnecessary objects

Android’s performance tips briefly mention Avoid Creating Unnecessary Objects. However, item 6 of Joshua Bloch’s recently updated book, Effective Java, has far more practical examples I recommend you check out. The hardest to spot of these being autoboxing. How does it apply to Kotlin where the compiler decides for you whether, for example, an Int turns into a primitive type, int, or a reference type, Integer.

Typically the compiler sticks to the advice of Effective Java preferring primitives to reference types. Lukas Lechner points out three exceptions:

If you use Nullable types such as Int?, then this will always compile as Integer as there’s no way for a primitive reference to hold null. When developing with Kotlin ask yourself, “does this need to be null?”

Collections typically allow nulls and use generics storing reference types only. To avoid auto-boxing on Android, you can use Sparse arrays such as SparseIntArray which compared to HashMap<Integer, Intger> uses significantly less memory too, 8072 bytes vs 64136 bytes for 1000 elements according to Romain Guy. However, although more memory efficient they are not as fast as HashMap especially with a lot of elements.

The issue with generics is the type argument must be a reference type. Usually, the use of generics will be apparent, but one hidden case is in the use of lambda functions. Consider the following code:

fun awesomeAlgorithm(factor: Int): (Int, Int) -> Int {
return { a, b -> a + b * factor }

This generates byte-code where the lambda’s input and output will be boxed just to be unboxed again, not what you would call efficient. Function2 is the interface used for functions with two input parameters, Kotlin defines these interfaces from 0 to 22.

public static final Function2 awesomeAlgorithm(final int factor) {
return new Function2() {
public Object invoke(Object var1, Object var2) {
return Integer.valueOf(this.invoke(
((Number) var1).intValue(),
((Number) var2).intValue()

public final int invoke(int a, int b) {
return a + b * factor;

Depending on how you are using lambdas the solution is relatively straightforward, define functions with lambda parameters as inline. Exploring Kotlin’s hidden costs — Part 1 demonstrates this in more detail.

However, you cannot merely inline the example given above. An alternative, albeit slightly more work, is to follow the guidance of Kotlin λ and auto-boxing of parameters and result and, for example, create your own explicit IntBinaryOperator.

With Kotlin don’t just be careful when explicitly creating objects but pay particular care when you are using lambdas as these are more likely to hide the already well-hidden auto-boxed types.

Each week I am looking at “items” from Joshua Bloch’s well-respected book, Effective Java to see how it applies to Kotlin. You can find the rest of the items I’ve covered at Effective Kotlin. Please let me know your thoughts.

Matt Dolan has been eating doughnuts and developing with Android since the dark days of v1.6.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store