Освой Kotlin играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

Лямбды

Kotlin поддерживает лямбды. Общий вид выражения.


{ arguments -> function body }

Лямбды всегда находятся внутри фигурных скобок. Слева находятся аргументы, справа - тело функции. Разделят их специальное выражение ->. Например, создадим выражение.


{x: Int -> x + 5}

Открыли фигурную скобку, записали параметр в виде числа Int, а затем указали, что с ним нужно делать в правой части - прибавить к числу 5. Параметр может быть один, как в нашем пример, несколько или вообще не быть.

Лямбда-выражение можно сохранить в переменной, а затем обращаться к ней как к обычной функции. Можно вызвать лямбда-выражение при помощи invoke().


val lambda = { println("Hello Kitty!") }
lambda.invoke()

Лямбда-выражение может послужить удобной заменой для паттернов Listener или Callback.

Примеры


// Нет аргументов и возвращает 1
{ 1 } // () -> Int

// Один аргумент в виде строки, который выводится на экран
{ s: String -> println(s) }  // (String)->Unit

// два аргумента типа Int и возвращает произведение чисел
{ a: Int, b: Int -> a * b } // (Int, Int)->Int

Код с лямбдами становится короче и читабельнее.


button.setOnClickListener { /* код для щелчка кнопки */ }

Другой пример.


val sum = { x: Int, y: Int -> x + y }
println(sum(1, 2))
// 3

Лямбды можно записывать в несколько строк.


val test = { a: Int, b: Int ->
    println("$a + $b")
	a + b
}

Этот же пример можно записать одной строкой, разделяя команды точкой с запятой.

val test = { a: Int, b: Int -> println("$a + $b"); a + b }

setOnClickListener

Рассмотрим применение лямбда-выражений на примере обработчика щелчка кнопки.

Код на Java 7 и ниже.


button.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
        /* код для щелчка кнопки */
    }
});

Если использовать такой же код на Kotlin, то получим.


button.setOnClickListener(object : View.OnClickListener {
    override fun onClick(v: View?) {
        println("Hello Kitty")
    }
})

Студия предложит сконвертировать код, используя лямбду. В моём случае студия сразу сконвертировала в самый короткий вариант. Но мы рассмотрим все случаи, например, возможен такой вариант.


button.setOnClickListener({ v -> println("Hello Kitty") })

Если в последнем параметре функции используется функция, то её можно вынести за круглые скобки. Получится следующее.


button.setOnClickListener() { v -> println("Hello Kitty") }

Если у функции несколько параметров, то только последнюю можно вынести за круглые скобки.

А мы продолжаем уменьшать код. Если у функции только один параметр и он является функцией, то круглые скобки можно убрать.


button.setOnClickListener { v -> println("Hello Kitty") }

Если в самом лямбда-выражении не используется параметр в левой части, то его можно удалить. Это справедливо для выражения с одним параметром. В нашем примере v (View) не используется, сокращаем код ещё раз.


button.setOnClickListener { println("Hello Kitty") }

Функция с одним параметром. Ключевое слово it

Рассмотрим частный случай, когда функция только получает параметр. Мы можем не использовать левую часть, а использовать ключевое слово it. Например, мы используем v для его передачи другой функции.


button.setOnClickListener { v -> doSomething(v) }

private fun doSomething(v: View?) {
    println("Hello Kitty")
}

Убираем левую часть и используем it.


button.setOnClickListener { doSomething(it) }

Все варианты в одном месте.


button.setOnClickListener({ v -> println("Hello Kitty") })
button.setOnClickListener() { v -> println("Hello Kitty") }
button.setOnClickListener { v -> println("Hello Kitty") }
button.setOnClickListener { println("Hello Kitty") }

button.setOnClickListener { v -> doSomething(v) }
button.setOnClickListener { doSomething(it) }

Другой пример использования - пройтись по элементам коллекции. Например, воспользуемся forEach:


val cats = listOf("Barsik", "Murzik", "Ryzhik")
cats.forEach { println(it) }

// Выводит
Barsik
Murzik
Ryzhik

Без использования ключевого слова it пришлось бы писать длинный вариант.


cats.forEach { cat -> println(cat) }
Реклама