Чтобы добавить фон к другому ответу:
Это одна из немного неловких областей в Kotlin, с точки зрения взаимодействия с Java. Но это печальное последствие того, что Kotlin стал лучшим языком сам по себе! Позвольте мне попытаться объяснить ...
Когда Java добавил лямбды, они сделали это таким образом (как и в случае с дженериками до этого), чтобы внести минимум изменений в работу языка. Поэтому они не делали функции первоклассными типами. Вместо этого они закрепили существующую практику использования интерфейсов. Например, если вы хотите, чтобы о чем-то сообщали ActionEvent
s, вы бы реализовали интерфейс ActionListener
. Это единственный метод с именем actionPerformed()
, принимающий параметр ActionEvent
.
Они не хотели менять то, как все это работало, поэтому в Java 8+ лямбда - это просто более лаконичный способ реализации некоторого интерфейса. Контекст (то есть метод, который вы вызываете, или тип переменной, которой вы его назначаете) сообщает компилятору, какой тип интерфейса вы хотите - это должен быть «функциональный интерфейс» с Single Abstract Method (SAM) - и затем компилятор генерирует реализацию. Есть несколько оптимизаций, но это в основном то, что вы делали в Java 7-. Это не так уж плохо работает, но есть много неудобных угловых случаев, потому что функции не являются полными первоклассными объектами.
Котлин, с другой стороны, имеет правильные типы функций. Это гораздо более мощный и гибкий инструмент, но он не соответствует способу работы Java.
Компилятор Kotlin имеет несколько особых случаев, позволяющих автоматически преобразовывать лямбду в реализацию Java SAM-интерфейса. (Однако это не относится к реализации интерфейсов Kotlin, что вызывает некоторую путаницу.)
В тех случаях, когда вы передаете лямбду, реализующую SAM, непосредственно методу, компилятор может определить его тип. (Как во втором примере @ Slaw.)
Но в других случаях вам нужно указать имя интерфейса перед открывающей фигурной скобкой. (Как в первом примере @ Slaw.)