Если вы опытный разработчик приложений для Android, вы, вероятно, привыкли к многословию Java 7. В результате вы можете найти краткий синтаксис Kotlin, который ориентирован на функциональных программистов, немного тревожный.
Одной из распространенных проблем, с которыми сталкиваются новички при изучении Kotlin, является понимание того, как он ожидает, что вы будете работать с интерфейсами Java, которые содержат один метод. Такие интерфейсы повсеместны в мире Android и часто называются интерфейсами SAM, где SAM — сокращение от Single Abstract Method.
В этом коротком руководстве вы узнаете все, что нужно для правильного использования SAM-интерфейсов Java в коде Kotlin.
1. Что такое преобразование SAM?
Если вы хотите использовать интерфейс Java, содержащий один метод в коде Kotlin, вам не нужно вручную создавать анонимный класс, который его реализует. Вместо этого вы можете использовать лямбда-выражение. Благодаря процессу, называемому преобразованием SAM, Kotlin может прозрачно преобразовать любое лямбда-выражение, сигнатура которого совпадает с сигнатурой единственного метода интерфейса, в экземпляр анонимного класса, который реализует интерфейс.
Например, рассмотрим следующий Java-интерфейс с одним методом:
1
2
3
|
public interface Adder {
public void add(int a, int b);
}
|
Наивный и Java 7-подобный подход к использованию вышеуказанного интерфейса будет включать в себя работу с выражением object
и будет выглядеть следующим образом:
1
2
3
4
5
6
7
|
// Creating instance of an anonymous class
// using the object keyword
val adder = object : Adder {
override fun add(a: Int, b: Int): Int {
return a + b
}
}
|
Это много ненужного кода, который также не очень читабелен. Однако, используя средства преобразования Kotlin SAM, вы можете вместо этого написать следующий эквивалентный код:
1
2
|
// Creating instance using a lambda
val adder = Adder { a, b -> a + b }
|
Как вы можете видеть, теперь мы заменили анонимный класс коротким лямбда-выражением, которому предшествует имя интерфейса. Обратите внимание, что число аргументов, которые принимает лямбда-выражение, равно количеству параметров в сигнатуре метода интерфейса.
2. Преобразования SAM в вызовах функций
Работая с классами Java, имеющими методы, которые принимают типы SAM в качестве аргументов, вы можете еще больше упростить приведенный выше синтаксис. Например, рассмотрим следующий класс Java, который содержит метод, который ожидает объект, реализующий интерфейс Adder
:
01
02
03
04
05
06
07
08
09
10
11
|
public class Calculator {
private Adder adder;
public void setAdder(Adder adder) {
this.adder = adder;
}
public void add(int a, int b) {
Log.d(«CALCULATOR», «Sum is » + adder.add(a,b));
}
}
|
В вашем коде Kotlin теперь вы можете напрямую передавать лямбда-выражение в метод setAdder()
без setAdder()
префикса имени интерфейса Adder
.
1
2
|
val calculator = Calculator()
calculator.setAdder({ a, b -> a+b })
|
Стоит отметить, что при вызове метода, который принимает тип SAM в качестве единственного аргумента, вы можете пропустить скобки, чтобы сделать ваш код еще более сжатым.
1
|
calculator.setAdder { a, b -> a+b }
|
3. SAM преобразования без лямбды
Если вы думаете, что лямбда-выражения сбивают с толку, у меня есть для вас хорошая новость: преобразования SAM также отлично работают с обычными функциями. Например, рассмотрим следующую функцию, подпись которой совпадает с сигнатурой метода интерфейса Adder
:
1
2
3
4
5
6
7
|
fun myCustomAdd(a:Int , b:Int):Int =
if (a+b < 100)
-1
else if (a+b < 200)
0
else
a+b
|
Kotlin позволяет вам напрямую передавать myCustomAdd()
в качестве аргумента setAdder()
класса Calculator
. Не забудьте сослаться на метод с помощью оператора ::
. Вот как:
1
|
calculator.setAdder (this::myCustomAdd)
|
4. Переменная
Часто интерфейсы SAM содержат однопараметрические методы. Метод с одним параметром, как следует из его названия, имеет только один параметр в своей сигнатуре. Работая с такими интерфейсами, Kotlin позволяет вам пропустить параметр в сигнатуре вашего лямбда-выражения и использовать неявную переменную, называемую it
в теле выражения. Чтобы прояснить ситуацию, рассмотрим следующий интерфейс Java:
1
2
3
|
public interface Doubler {
public int doubleIt(int number);
}
|
При использовании интерфейса Doubler
в вашем коде Kotlin вам не нужно явно указывать параметр number
в сигнатуре вашего лямбда-выражения. Вместо этого вы можете просто сослаться на это как на it
.
1
2
3
4
5
|
// This lambda expression using the it variable
val doubler1 = Doubler { 2*it }
// is equivalent to this ordinary lambda expression
val doubler2 = Doubler { number -> 2*number }
|
5. Интерфейсы SAM в Котлине
Как разработчик Java, вы можете быть склонны создавать SAM-интерфейсы в Kotlin. Однако делать это обычно не очень хорошая идея. Если вы создаете интерфейс SAM в Kotlin или создаете метод Kotlin, который ожидает, что объект, реализующий интерфейс SAM в качестве аргумента, средство преобразования SAM будет вам недоступно — преобразование SAM является функцией взаимодействия Java и ограничено Java только классы и интерфейсы.
Поскольку Kotlin поддерживает функции более высокого порядка — функции, которые могут принимать другие функции в качестве аргументов — вам никогда не понадобится создавать в нем интерфейсы SAM. Например, если класс Calculator
переписан в Kotlin, его setAdder()
может быть написан так, что он напрямую принимает функцию в качестве аргумента вместо объекта, реализующего интерфейс Adder
.
1
2
3
4
5
6
7
8
9
|
class Calculator {
var adder:(a:Int, b:Int)->Int = {a,b -> 0}
// Default implementation
// Setter is available by default
fun add(a:Int, b:Int) {
Log.d(«CALCULATOR», «Sum is » + adder(a,b))
}
}
|
Используя вышеупомянутый класс, вы можете установить adder
для функции или лямбда-выражения, используя оператор =
. Следующий код показывает вам, как:
1
2
3
4
|
val calculator = Calculator()
calculator.adder = this::myCustomAdd
// OR
calculator.adder = {a,b -> a+b}
|
Вывод
API-интерфейсы Android в основном написаны на Java, и многие широко используют интерфейсы SAM. То же самое можно сказать и о большинстве сторонних библиотек. Используя методы, которые вы изучили в этом руководстве, вы можете работать с ними в своем коде Kotlin в краткой и удобной для чтения форме.
Чтобы узнать больше о возможностях взаимодействия Java с Kotlin, обратитесь к официальной документации . И ознакомьтесь с некоторыми другими нашими учебниками по разработке приложений для Android!