Idioms

A collection of random and frequently used idioms in Kotlin. If you have a favorite idiom, contribute it by sending a pull request.

Creating DTOs (POJOs/POCOs)

  1. data class Customer(val name: String, val email: String)

provides a Customer class with the following functionality:

  • getters (and setters in case of vars) for all properties
  • equals()
  • hashCode()
  • toString()
  • copy()
  • component1(), component2(), …, for all properties (see Data classes)

Default values for function parameters

  1. fun foo(a: Int = 0, b: String = "") { ... }

Filtering a list

  1. val positives = list.filter { x -> x > 0 }

Or alternatively, even shorter:

  1. val positives = list.filter { it > 0 }

Checking element presence in a collection.

  1. if ("john@example.com" in emailsList) { ... }
  2. if ("jane@example.com" !in emailsList) { ... }

String Interpolation

  1. println("Name $name")

Instance Checks

  1. when (x) {
  2. is Foo -> ...
  3. is Bar -> ...
  4. else -> ...
  5. }

Traversing a map/list of pairs

  1. for ((k, v) in map) {
  2. println("$k -> $v")
  3. }

k, v can be called anything.

Using ranges

  1. for (i in 1..100) { ... } // closed range: includes 100
  2. for (i in 1 until 100) { ... } // half-open range: does not include 100
  3. for (x in 2..10 step 2) { ... }
  4. for (x in 10 downTo 1) { ... }
  5. if (x in 1..10) { ... }

Read-only list

  1. val list = listOf("a", "b", "c")

Read-only map

  1. val map = mapOf("a" to 1, "b" to 2, "c" to 3)

Accessing a map

  1. println(map["key"])
  2. map["key"] = value

Lazy property

  1. val p: String by lazy {
  2. // compute the string
  3. }

Extension Functions

  1. fun String.spaceToCamelCase() { ... }
  2. "Convert this to camelcase".spaceToCamelCase()

Creating a singleton

  1. object Resource {
  2. val name = "Name"
  3. }

Instantiate an abstract class

  1. abstract class MyAbstractClass {
  2. abstract fun doSomething()
  3. abstract fun sleep()
  4. }
  5. fun main() {
  6. val myObject = object : MyAbstractClass() {
  7. override fun doSomething() {
  8. // ...
  9. }
  10. override fun sleep() { // ...
  11. }
  12. }
  13. myObject.doSomething()
  14. }

If not null shorthand

  1. val files = File("Test").listFiles()
  2. println(files?.size)

If not null and else shorthand

  1. val files = File("Test").listFiles()
  2. println(files?.size ?: "empty")

Executing a statement if null

  1. val values = ...
  2. val email = values["email"] ?: throw IllegalStateException("Email is missing!")

Get first item of a possibly empty collection

  1. val emails = ... // might be empty
  2. val mainEmail = emails.firstOrNull() ?: ""

Execute if not null

  1. val value = ...
  2. value?.let {
  3. ... // execute this block if not null
  4. }

Map nullable value if not null

  1. val value = ...
  2. val mapped = value?.let { transformValue(it) } ?: defaultValue
  3. // defaultValue is returned if the value or the transform result is null.

Return on when statement

  1. fun transform(color: String): Int {
  2. return when (color) {
  3. "Red" -> 0
  4. "Green" -> 1
  5. "Blue" -> 2
  6. else -> throw IllegalArgumentException("Invalid color param value")
  7. }
  8. }

‘try/catch’ expression

  1. fun test() {
  2. val result = try {
  3. count()
  4. } catch (e: ArithmeticException) {
  5. throw IllegalStateException(e)
  6. }
  7. // Working with result
  8. }

‘if’ expression

  1. fun foo(param: Int) {
  2. val result = if (param == 1) {
  3. "one"
  4. } else if (param == 2) {
  5. "two"
  6. } else {
  7. "three"
  8. }
  9. }

Builder-style usage of methods that return Unit

  1. fun arrayOfMinusOnes(size: Int): IntArray {
  2. return IntArray(size).apply { fill(-1) }
  3. }

Single-expression functions

  1. fun theAnswer() = 42

This is equivalent to

  1. fun theAnswer(): Int {
  2. return 42
  3. }

This can be effectively combined with other idioms, leading to shorter code. E.g. with the when-expression:

  1. fun transform(color: String): Int = when (color) {
  2. "Red" -> 0
  3. "Green" -> 1
  4. "Blue" -> 2
  5. else -> throw IllegalArgumentException("Invalid color param value")
  6. }

Calling multiple methods on an object instance (with)

  1. class Turtle {
  2. fun penDown()
  3. fun penUp()
  4. fun turn(degrees: Double)
  5. fun forward(pixels: Double)
  6. }
  7. val myTurtle = Turtle()
  8. with(myTurtle) { //draw a 100 pix square
  9. penDown()
  10. for (i in 1..4) {
  11. forward(100.0)
  12. turn(90.0)
  13. }
  14. penUp()
  15. }

Configuring properties of an object (apply)

  1. val myRectangle = Rectangle().apply {
  2. length = 4
  3. breadth = 5
  4. color = 0xFAFAFA
  5. }

This is useful for configuring properties that aren’t present in the object constructor.

Java 7’s try with resources

  1. val stream = Files.newInputStream(Paths.get("/some/file.txt"))
  2. stream.buffered().reader().use { reader ->
  3. println(reader.readText())
  4. }

Convenient form for a generic function that requires the generic type information

  1. // public final class Gson {
  2. // ...
  3. // public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
  4. // ...
  5. inline fun <reified T: Any> Gson.fromJson(json: JsonElement): T = this.fromJson(json, T::class.java)

Consuming a nullable Boolean

  1. val b: Boolean? = ...
  2. if (b == true) {
  3. ...
  4. } else {
  5. // `b` is false or null
  6. }

Swapping two variables

  1. var a = 1
  2. var b = 2
  3. a = b.also { b = a }

TODO(): Marking code as incomplete

Kotlin’s standard library has a TODO() function that will always throw a NotImplementedError. Its return type is Nothing so it can be used regardless of expected type. There’s also an overload that accepts a reason parameter:

  1. fun calcTaxes(): BigDecimal = TODO("Waiting for feedback from accounting")

IntelliJ IDEA’s kotlin plugin understands the semantics of TODO() and automatically adds a code pointer in the TODO tool window.