Spec-Zone.ru › Kotlin 2

Функциональные (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.

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

Начиная с версии 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(...) {...}

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

Также можно просто переписать приведенный выше пример, используя псевдоним типа для функционального типа:

typealias IntPredicate = (i: Int) -> Boolean

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

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

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

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

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

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

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

24 октября 2025 г.
Вложенные и внутренние классыСвойства

© 2010–2026 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