Шаг 60.
Основы Kotlin. Анонимные функции и функциональные типы. Лямбды против анонимных внутренних классов

    На этом шаге мы сравним использование лямбд и ананимных внутренних классов.

    Если до этого вы не использовали функциональные типы, то можете задаться вопросом: зачем их вообще использовать? Наш ответ: функциональные типы предлагают большую гибкость с меньшим объемом кода. Рассмотрим язык, который не поддерживает функциональные типы, например Java 8.

    Java 8 поддерживает объектно-ориентированное программирование и лямбда-выражения, но не позволяет объявлять параметры или переменные, способные хранить другие функции. Вместо этого в нем предлагается использовать анонимные внутренние классы, то есть безымянные классы, объявляемые внутри другого класса ради реализации единственного метода. Анонимные встроенные классы можно передавать как экземпляры, подобно лямбдам. Например, в Java 8, чтобы просто передать один метод, вам придется написать:

Greeting greeting = (playerName, numBuildings) -> { 
  int currentYear = 2021;
  System.out.println("Adding " + numBuildings + " houses"); 
  return "Welcome to SimVillage, " + playerName +
    "! (copyright " + currentYear + ")";
};

public interface Greeting {
  String greet(String playerName, int numBuildings);
}

greeting.greet("Guyal", 6);

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

    Например, посмотрите на интерфейс Runnable в Java:

public interface Runnable {
  public abstract void run();
}

    Объявление лямбды в Java 8 требует объявления интерфейса. В Kotlin такое дополнительное усилие для описания одного абстрактного метода не требуется. Следующий код на Kotlin эквивалентен коду на Java:

fun runMyRunnable(runnable: () -> Unit) = { runnable() } 
runMyRunnable { println("hey now") }

    Объедините этот синтаксис с другими возможностями, изученными в предыдущих шагах, - встроенными функциями, ключевым словом it, замыканиями, - и вы получите более совершенный способ, чем объявление встроенных классов ради реализации единственного метода.

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

    Со следующего шага мы начнем рассматривать null-безопасность и исключения.




Предыдущий шаг Содержание Следующий шаг