Лямбда-выражения в Java.
Лямбда-выражение - компактный способ передать поведение из одного места программы в другое.
Лямбда-выражения и связанные с ними средства, внедрённые в версии JDK 8, значительно усовершенствовали язык Java по следующим причинам.
Во-первых, они ввели в синтаксис новые элементы, повышающие выразительную силу языка.
Во-вторых, внедрение лямбда-выражений позволило наделить новыми возможностями библиотеку прикладного программного интерфейса API.
Лямбда-выражение, по существу, является безымянным методом. Но этот метод не выполняется самостоятельно, а служит для реализации метода, определяемого в функциональном интерфейсе. Таким образом, лямбда-выражение приводит к некоторой форме анонимного класса.
Несмотря на сходство лямбда-выражений с анонимными классами, их нельзя назвать более удобными синтаксически, чем анонимные классы. В действительности лямбда-выражения реализуются с помощью дескрипторов методов, а также новой специальной инструкции байт-кода JVM, называемой invokedynamic.
В версии Java 7 был внедрён совершенно новый механизм для самоанализа и доступа к методам. Первоначально этот механизм предназначался для применения вместе с динамическими языками, которые могли быть задействованы в диспетчеризации методов во время выполнения. Для поддержки данного механизма на уровне виртуальной машины JVM была внедрена новая байт-кодовая инструкция invokedynamic.
Лямбда-выражения представляют создание объекта особого типа. Тип экземпляра создаваемого объекта называется целевым типом лямбда-выражения. В качестве целевых типов лямбда-выражений допускаются лишь некоторые типы данных.
Целевые типы иначе называют функциональными интерфейсами.
Функциональным называется такой интерфейс, который содержит один и только один абстрактный метод. Как правило, в таком методе определяется предполагаемое назначение интерфейса. Следовательно, функциональный интерфейс представляет единственное действие.
Например, стандартный интерфейс Runnable является функциональным, поскольку в нём определяется единственный метод run(), который в свою очередь, определяет действие самого интерфейса Runnable. Кроме того, в функциональном интерфейсе определяется целевой тип лямбда-выражения. В связи с этим необходимо подчеркнуть следующее: лямбда-выражение можно использовать только в том контексте, в котором определён его целевой тип.
Когда компилятор javac встречает лямбда-выражение в исходном коде, он интерпретирует его как тело метода с особой сигнатурой. Компилятор анализирует код, окружающий лямбда-выражение. Чтобы считаться допустимым кодом, лямбда-выражение должно удовлетворять следующим критериям.
- Должно присутствовать там, где предполагается экземпляр интерфейсного типа.
- У предполагаемого экземпляра должен быть лишь один обязательный метод.
- Сигнатура предполагаемого интерфейсного метода должна быть точно такой же, как и у лямбда-выражения.
В таком случае создаётся экземпляр типа, реализующего предполагаемый интерфейс, а тело лямбда-выражения используется как реализация обязательного метода. При этом лямбда-выражение преобразуется в надлежащий интерфейсный тип.
Использование анонимного внутреннего класса для связывания поведения с нажатием кнопки.
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
System.out.println("button clicked");
}
}
Использование лямбда-выражения для связывания поведения с нажатием кнопки
button.addActionListener(event -> System.out.println("button clicked"));
Вместо объекта, реализующего интерфейс, мы передаем блок кода - функцию без имени. Здесь event - имя параметра, такое же, как в примере с анонимным внутренним классом, а стрелка отделяет параметр от тела лямбда-выражения, содержащего код, исполняемый при нажатии кнопки.