Spec-Zone.ru › Kotlin 1.6

Функциональные (SAM) интерфейсы

Интерфейс с единственным абстрактным методом называется функциональным интерфейсом или интерфейсом с единственным абстрактным методом (SAM). Функциональный интерфейс может иметь несколько неабстрактных членов, но только один абстрактный.

Для объявления функционального интерфейса в Kotlin используйте модификатор fun.

fun interface KRunnable {
   fun invoke()
}

Преобразования SAM

Для функциональных интерфейсов можно использовать преобразования SAM, которые помогают сделать ваш код более лаконичным и читаемым, используя лямбда-выражения.

Вместо создания класса, который вручную реализует функциональный интерфейс, вы можете использовать лямбда-выражение. С помощью преобразования SAM Kotlin может преобразовать любое лямбда-выражение, чья сигнатура соответствует сигнатуре единственного метода интерфейса, в код, который динамически создаёт реализацию интерфейса.

Например, рассмотрим следующий Kotlin функциональный интерфейс:

fun interface IntPredicate {
   fun accept(i: Int): Boolean
}

Если вы не используете преобразование SAM, вам нужно написать код такого вида:

// Creating an instance of a class
val isEven = object : IntPredicate {
   override fun accept(i: Int): Boolean {
       return i % 2 == 0
   }
}

Используя преобразование SAM Kotlin, вы можете написать следующий эквивалентный код:

// Creating an instance using lambda
val isEven = IntPredicate { it % 2 == 0 }

Короткое лямбда-выражение заменяет весь ненужный код.

fun interface IntPredicate {
   fun accept(i: Int): Boolean
}

val isEven = IntPredicate { it % 2 == 0 }

fun main() {
   println("Is 7 even? - ${isEven.accept(7)}")
}

Вы также можете использовать преобразования SAM для Java интерфейсов.

Миграция из интерфейса с конструктором-функцией в функциональный интерфейс

Поддержка вызовов ссылок на конструкторы функциональных интерфейсов находится в стадии эксперимента. Она может быть удалена или изменена в любое время. Требуется явное включение (см. подробности ниже), и вы должны использовать её только для оценочных целей. Мы будем признательны за ваши отзывы по этому вопросу в YouTrack.

Начиная с версии 1.6.20, Kotlin поддерживает ссылки на вызываемые объекты к конструкторам функциональных интерфейсов, что добавляет совместимый с исходным кодом способ миграции от интерфейса с функцией-конструктором к функциональному интерфейсу. Рассмотрим следующий код:

interface Printer { 
    fun print() 
}

fun Printer(block: () -> Unit): Printer = object : Printer { override fun print() = block() }

При включённых ссылках на вызываемые объекты конструкторов функциональных интерфейсов, этот код можно заменить всего лишь объявлением функционального интерфейса:

fun interface Printer { 
    fun print()
}

Его конструктор будет создан неявно, и любой код, использующий ссылку на функцию ::Printer, будет компилироваться. Например:

documentsStorage.addPrinter(::Printer)

Сохраните бинарную совместимость, пометив устаревшую функцию Printer аннотацией @Deprecated с DeprecationLevel.HIDDEN:

@Deprecated(message = "Your message about the deprecation", level = DeprecationLevel.HIDDEN)
fun Printer(...) {...}

Используйте опцию компилятора -XXLanguage:+KotlinFunInterfaceConstructorReference, чтобы включить эту функцию.

Функциональные интерфейсы против псевдонимов типов

Функциональные интерфейсы и псевдонимы типов служат разным целям. Псевдонимы типов — это просто имена существующих типов; они не создают нового типа, в то время как функциональные интерфейсы — это так. Вы можете предоставить расширения, которые специфичны для конкретного функционального интерфейса, чтобы они не были применимы к обычным функциям или их псевдонимам типов.

Псевдонимы типов могут иметь только один член, в то время как функциональные интерфейсы могут иметь несколько неабстрактных членов и один абстрактный член. Функциональные интерфейсы также могут реализовывать и расширять другие интерфейсы.

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

  • Если ваш API должен принимать функцию (любую функцию) с некоторыми специфическими параметрами и типами возвращаемых значений — используйте простой функциональный тип или определите псевдоним типа, чтобы дать более короткое имя соответствующему функциональному типу.

  • Если ваш API принимает более сложный объект, чем функция — например, у него есть нетривиальные контракты и/или операции с ним, которые нельзя выразить в сигнатуре функционального типа — объявите отдельный функциональный интерфейс для него.

Последнее изменение: 07 апреля 2022 г.
Интерфейсы Модификаторы видимости

© 2010–2022 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/fun-interfaces.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API