Kotlin

Eine Snippet-Sammlung für Kotlin.

Links:

Funktionen

fun foo(a: Int): Int {
    return a
}

// Function without return value
fun foo(a: Int): Unit {
    ...
}
fun foo(a: Int) {
    ...
}

// Function with expression body and inferred return type
fun sum(a: Int, b: Int) = a + b

// Function with conditional expression body and inferred return type
fun maxOf(a: Int, b: Int) = if (a > b) a else b

// Function using when in expression body
fun describe(obj: Any): String =
    when (obj) {
        1          -> "One"
        "Hello"    -> "Greeting"
        is Long    -> "Long"
        !is String -> "Not a string"
        else       -> "Unknown"
    }

Variablen

Konstanten:

val a: Int = 1
val b = 2       // Inferred type `Int`
val c: Int      // Type required when no initializer is provided
c = 3           // deferred assignment

Variablen:

var x = 5       // Inferred type `Int`

Typen

// Optionals
val a: MyType?

// Arrays
val a: Array<Int> = arrayOf()

// Funktionsreferenz
val a: (param: Int) -> Unit   // No return value - Unit is equivalent to Java's `void`

Prüfungen

Typ-Prüfung:

if (obj is String) {
}
if (obj !is String) {
}

Ternärer Operator:

val result = if (bla) "foo" else "bar"

Elvis-Operator ?: (wertet rechte Seite aus, wenn linke Seite null ergibt):

val result = value ?: "default value"

Ranges

for (x in 1..5) { ... }          // Closed range: Includes 5
for (x in 1 until 5) { ... }     // Half-open range: does not include 5
for (x in 1..10 step 2) { ... }
for (x in 9 downTo 0 step 3) { ... }

Strings

var a = "File ${myFile.getAbsolutePath()} has $size bytes"

var multiline =
    """
        Hello
        Multiline
    """.trimIndent()

Collections

List:

val items = listOf("apple", "banana", "kiwifruit")   // Read-only

for (item in items) {
    println(item)
}
for (index in items.indices) {
    println("item at $index is ${items[index]}")
}

if (myIndex !in 0..list.lastIndex) { ... }

when {
    "orange" in items -> println("juicy")
    "apple" in items -> println("apple is fine too")
}

fruits
    .filter { it.startsWith("a") }
    .sortedBy { it }
    .map { it.toUpperCase() }
    .forEach { println(it) }

Maps:

val map = mapOf("a" to 1, "b" to 2, "c" to 3)   // Read-only

for ((key, value) in map) { ... }

Generics

Generische Methode:

fun <A, B> foo(a: A): B {
    ...
}

Generische Methode aufrufen (wenn Typ nicht erkannt werden kann):

let b = foo<String?, Int>(null)

Generische Klasse:

class Foo<A> {
    ...
}

Sichtbarkeit

Klassen

Instanziierung

val rectangle = Rectangle(5.0, 2.0) //no 'new' keyword required

Konstruktoren

package my.package

import java.util.*

// Class with primary constructor (taking a String and an Int)
// and multiple initializer blocks
class MyClass(name: String, let age: Int) {  // age is a constant
    var uppercaseName = name.toUpperCase()

    init {
        ...
    }

    var bar = 42

    init {
        ...
    }
}

// constructor keyword needed
class Customer public @Inject constructor(name: String) { ... }

// Class with secondary constructor
class Person(val name: String) {
    constructor(name: String, parent: Person) : this(name) {
        parent.children.add(this)
    }
}

// Klasse mit privatem Konstruktor
class MyUtilClass private constructor () {
}

Properties

Details siehe Kotlin Doku

class MyClass {
    var a = 5  // Simple mutable property
    val b = 5  // Simple read-only property

    // Custom getter
    val isEmpty: Boolean
        get() = this.size == 0   // Computed with getter
    val isEmpty get() = this.size == 0 // Short version with inferred type

    // Custom setter
    var stringRepresentation: String
        get() = this.toString()
        set(value) {
            setDataFromString(value) // parses the string and assigns values to other properties
        }

    // Custom setter using a backing field (accessed by `field`)
    var counter = 0 // Note: the initializer assigns the backing field directly
        set(value) {
            if (value >= 0) field = value
        }

    var setterVisibility: String = "abc"
        private set // the setter is private and has the default implementation

    val p: String by lazy {
        // Compute the string lazy
    }
}

open class Foo {
    open val x: Int get() { ... }
}
class Bar1 : Foo() {
    override val x: Int = ...
}

Methoden

open class Base {        // open -> Klasse kann überschrieben werden
    open fun v() {}      // open -> Methode kann überschrieben werden
    fun nv() {}          // Methode kann nicht überschrieben werden
}
class Derived() : Base() {
    override fun v() {}
}
open class AnotherDerived() : Base() {
    final override fun v() {}  // final -> Methode kann nicht überschrieben werden
}

Statische Variablen und Methoden

class MyClass private constructor() {
    companion object {
        // static stuff goes here
        var bla = "Hello"
    }
}

println(MyClass.bla)

Innere Klassen

class Bar : Foo() {
    override fun f() { /* ... */ }
    override val x: Int get() = 0

    inner class Baz {
        fun g() {
            super@Bar.f() // Calls Foo's implementation of f()
            println(super@Bar.x) // Uses Foo's implementation of x's getter
        }
    }
}

Anonyme inner Klasse:

class A (delegate: A.Delegate) {

    interface Delegate {
        fun doStuff()
    }

}

class MyClass {

    private var bla: A

    init {
        bla = A(object : MyInterface {
            override fun doStuff() {
                this@MyClass.doStuff()
            }
        })
    }

    private fun doStuff() {
    }

}

Interfaces

Details siehe Doku über Interfaces

interface MyInterface {
    val prop: Int // abstract

    val propertyWithImplementation: String
        get() = "foo"

    fun foo()
    fun bar() {
      // optional body
    }
}

Implementierung eines Interface:

class Child : MyInterface {
    override val prop: Int = 29

    override fun foo() {
        // body
    }
}

Anonyme Implementierung eines Interface:

val myInstance = object : MyInterface {
    override val prop: Int = 29

    override fun foo() {
        // body
    }
}

Konflikte beheben:

interface A {
    fun foo() { print("A") }
}

interface B {
    fun foo() { print("B") }
}

class C : A, B {
    override fun foo() {
        super<A>.foo()
    }
}

Enum-Klassen

Details siehe Doku von Enum-Klassen.

Einfache Enum:

enum class Direction {
    NORTH, SOUTH, WEST, EAST
}

Enum mit Typ und festgelegten Werten:

enum class Color(val rgb: Int) {
    RED(0xFF0000),
    GREEN(0x00FF00),
    BLUE(0x0000FF)
}

Object Declarations (Singletons)

object MySQLOpenHandler : SQLiteOpenHelper(App.instance, "MyDB", null, 1) {

    override fun onCreate(db: SQLiteDatabase?) {
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
    }

}