В конце предыдущей части в примере использовалось лямбда-выражение. Напомню, что лямбда-выражение — это сокращённая запись анонимной, то есть необъявленной функции, не имеющей имени. Анонимная функция — это функция, не имеющая имени, тело которой непосредственно используется в качестве аргумента другой функции.
Пример анонимной функции:
Функции с одной строкой кода в своём теле лучше записывать вообще в одну строку:
Использование анонимной функции:
Использование сокращённой записи анонимной функции в виде лямбда-выражения:
В качестве третьего параметра вписана анонимная функция, которая, например, будет использоваться внутри функции operationSum для суммирования первых двух параметров.
Лямбда-выражения заключаются в фигурные скобки и могут быть многострочными. Функции, принимающие в качестве параметра другие функции или лямбды называются функциями высшего порядка.
В случае, если в лямбда-выражение передаётся только один параметр, запись можно сократить ещё больше, убрав оператор -> и всё, что слева от него. В этом случае доступ к переданному параметру внутри тела лямбда-выражения осуществляется через автоматически созданную переменную it:
Если лямбда-выражение многострочное, состоит из нескольких инструкций, то из него возвращается то значение, которое генерируется последней инструкцией.
Лямбда-выражения можно присваивать переменным:
Помимо функций высшего порядка, лямбда-выражения можно передавать и в интерфейсы с одним абстрактным методом для автоматической реализации этого метода переданным кодом, если типы параметров передаваемой функции или лямбда-выражения совпадают с типами параметров абстрактного метода интерфеса. Пока это относится только к Java-интерфейсам, но, возможно, в будущем это будет относиться и к Котлин-интерфейсам. Реальный пример кода (использующего стандартную библиотеку архитектурных компонентов LiveData) с передачей лямбда-выражения в интерфейс наблюдателя за данными:
В вышеприведённом примере мы реализуем интерфейс Observer, передав в него лямбда-выражение readoutsList -> readoutsList?.let { recyclerViewAdapter.addItems(it) }.
Интерфейс Observer имеет единственный абстрактный метод onChanged, принимающий данные любого типа (можно открыть Java-код интерфейса и посмотреть). Поэтому переданное интерфейсу лямбда-выражение автоматически преобразуются в реализацию единственного абстрактного метода интерфейса. Такое преобразование называется SAM-преобразованием (Single Abstract Method Conversions).
В лямбда-выражение передаются данные newLeavDataList. Они же оказываются на входе реализованного таким образом метода onChanged. Метод, в случае, если данные не null, добавляет их в адаптер. Кстати, для выполнения добавления только в том случае, если данные не null, реализовано с помощью метода данных let с использованием другого лямбда-выражения. О таком способе реализации null-безопасности рассказывалось в конце предыдущей части.
Пример анонимной функции:
fun(x: Int, y: Int): Int { return x + y }
Функции с одной строкой кода в своём теле лучше записывать вообще в одну строку:
fun(x: Int, y: Int): Int = x + y
Использование анонимной функции:
operationSum(7, 8, fun(x: Int, y: Int): Int = x + y)
Использование сокращённой записи анонимной функции в виде лямбда-выражения:
operationSum(7, 8, {x, y -> x + y})
В качестве третьего параметра вписана анонимная функция, которая, например, будет использоваться внутри функции operationSum для суммирования первых двух параметров.
Лямбда-выражения заключаются в фигурные скобки и могут быть многострочными. Функции, принимающие в качестве параметра другие функции или лямбды называются функциями высшего порядка.
В случае, если в лямбда-выражение передаётся только один параметр, запись можно сократить ещё больше, убрав оператор -> и всё, что слева от него. В этом случае доступ к переданному параметру внутри тела лямбда-выражения осуществляется через автоматически созданную переменную it:
operationInc(7, {it + 1})
Если лямбда-выражение многострочное, состоит из нескольких инструкций, то из него возвращается то значение, которое генерируется последней инструкцией.
Лямбда-выражения можно присваивать переменным:
val sum = { x: Int, y: Int -> x + y } val s = sum(2, 4) // s будет равно 6
Помимо функций высшего порядка, лямбда-выражения можно передавать и в интерфейсы с одним абстрактным методом для автоматической реализации этого метода переданным кодом, если типы параметров передаваемой функции или лямбда-выражения совпадают с типами параметров абстрактного метода интерфеса. Пока это относится только к Java-интерфейсам, но, возможно, в будущем это будет относиться и к Котлин-интерфейсам. Реальный пример кода (использующего стандартную библиотеку архитектурных компонентов LiveData) с передачей лямбда-выражения в интерфейс наблюдателя за данными:
/* * Подключение наблюдателя за изменениями данных. * Подлежащие наблюдению данные заключены в тип LiveData<t> и находятся в переменной этого типа leavDataList. * Для наблюдения за ними вызываем LiveData-метод observe, и передаём ему контекст владельца наблюдателя (это основная активность) * и реализацию интерфейса наблюдателя. */ leavDataList.observe(this@MainActivity, Observer { newLeavDataList -> newLeavDataList?.let { recyclerViewAdapter.addItems(it) } })
В вышеприведённом примере мы реализуем интерфейс Observer, передав в него лямбда-выражение readoutsList -> readoutsList?.let { recyclerViewAdapter.addItems(it) }.
Интерфейс Observer имеет единственный абстрактный метод onChanged, принимающий данные любого типа (можно открыть Java-код интерфейса и посмотреть). Поэтому переданное интерфейсу лямбда-выражение автоматически преобразуются в реализацию единственного абстрактного метода интерфейса. Такое преобразование называется SAM-преобразованием (Single Abstract Method Conversions).
В лямбда-выражение передаются данные newLeavDataList. Они же оказываются на входе реализованного таким образом метода onChanged. Метод, в случае, если данные не null, добавляет их в адаптер. Кстати, для выполнения добавления только в том случае, если данные не null, реализовано с помощью метода данных let с использованием другого лямбда-выражения. О таком способе реализации null-безопасности рассказывалось в конце предыдущей части.