Quick Tip: Write Cleaner Code With Kotlin SAM Conversions

Quick Tip: Write Cleaner Code With Kotlin SAM Conversions

If you are an experienced Android application developer, you're probably used to the verbosity of Java 7. As a result, you might be finding Kotlin's concise syntax, which is geared towards functional programmers, slightly unsettling.

One common problem beginners encounter while learning Kotlin is understanding how it expects you to work with Java interfaces that contain a single method. Such interfaces are ubiquitous in the Android world and are often referred to as SAM interfaces, where SAM is short for Single Abstract Method.

In this short tutorial, you'll learn everything you need to know to aptly use Java's SAM interfaces in Kotlin code.

1. What Is a SAM Conversion?

When you want to make use of a Java interface containing a single method in your Kotlin code, you don't have to manually create an anonymous class that implements it. Instead, you can use a lambda expression. Thanks to a process called SAM conversion, Kotlin can transparently convert any lambda expression whose signature matches that of the interface's single method into an instance of an anonymous class that implements the interface.

For example, consider the following one-method Java interface:

A naive and Java 7-like approach to using the above interface would involve working with an object expression and would look like this:

That's a lot of unnecessary code, which is also not very readable. By leveraging Kotlin's SAM conversion facility, however, you can write the following equivalent code instead:

As you can see, we've now replaced the anonymous class with a short lambda expression, which is prefixed with the name of the interface. Note that the number of arguments the lambda expression takes is equal to the number of parameters in the signature of the interface's method.

2. SAM Conversions in Function Calls

While working with Java classes having methods that take SAM types as their arguments, you can further simplify the above syntax. For example, consider the following Java class, which contains a method that expects an object implementing the Adder interface:

In your Kotlin code, you can now directly pass a lambda expression to the setAdder() method, without prefixing it with the name of the Adder interface.

It is worth noting that while calling a method that takes a SAM type as its only argument, you are free to skip the parenthesis to make your code even more concise.

3. SAM Conversions Without Lambdas

If you think lambda expressions are confusing, I've got good news for you: SAM conversions work just fine with ordinary functions too. For example, consider the following function whose signature matches that of the Adder interface's method:

Kotlin allows you to directly pass the myCustomAdd() function as an argument to the setAdder() method of the Calculator class. Don't forget to reference the method using the :: operator. Here's how:

4. The it Variable

Many times, SAM interfaces contain one-parameter methods. A one-parameter method, as its name suggests, has only one parameter in its signature. While working with such interfaces, Kotlin allows you to omit the parameter in your lambda expression's signature and use an implicit variable called it in the expression's body. To make things clearer, consider the following Java interface:

While using the Doubler interface in your Kotlin code, you don't have to explicitly mention the number parameter in your lambda expression's signature. Instead, you can simply refer to it as it.

5. SAM Interfaces in Kotlin

As a Java developer, you might be inclined to create SAM interfaces in Kotlin. Doing so, however, is usually not a good idea. If you create a SAM interface in Kotlin, or create a Kotlin method that expects an object implementing a SAM interface as an argument, the SAM conversion facility will not be available to you—SAM conversion is a Java-interoperability feature and is limited to Java classes and interfaces only.

Because Kotlin supports higher-order functions—functions that can take other functions as arguments—you'll never need to create SAM interfaces in it. For example, if the Calculator class is rewritten in Kotlin, its setAdder() method can be written such that it directly takes a function as its argument, instead of an object that implements the Adder interface.

While using the above class, you can set adder to a function or a lambda expression using the = operator. The following code shows you how:

Conclusion

Android's APIs are largely written in Java, and many use SAM interfaces extensively. The same can be said of most third-party libraries too. By using the techniques you learned in this tutorial, you can work with them in your Kotlin code in a concise and easy-to-read way.

To learn more about Kotlin's Java-interoperability features, do refer to the official documentation. And do check out some of our other tutorials on Android app development!

Source: Tuts Plus

About the Author