JavaRush /Java блог /Random /Кофе-брейк #182. Функциональные интерфейсы в Java

Кофе-брейк #182. Функциональные интерфейсы в Java

Статья из группы Random
Источник: DZone Вашему вниманию представлен обзор функциональных интерфейсов в Java: предназначение, примеры, лямбда-выражения и список предустановленных интерфейсов. Кофе-брейк #182. Функциональные интерфейсы в Java - 1Будучи объектно-ориентированным языком программирования, Java раньше не могла иметь независимые функции, поскольку в этом языке все, кроме некоторых примитивных типов данных и методов, вращается вокруг классов и объектов. Однако в Java 8 появилась новая концепция, называемая функциональным интерфейсом, а также некоторые другие фичи, такие как Lambda Expressions, Time API, Stream API и так далее. Что же это за функциональные интерфейсы и как их определить? Давай выясним!

Что такое интерфейс?

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

Interface A1
{
void method1();
String method2(String X);
}

Class A1 implements A
{
@Override
public void method1(){}
@Override
public String method2(String X) { return x; }
}
Если класс, реализующий интерфейс, не объявляет все методы интерфейса, код не запустится и выдаст ошибку: “error: A1 is not abstract and does not override an abstract method in A1." (ошибка: A1 не является абстрактным и не переопределяет абстрактный метод в A1). До JDK 8 интерфейсы не могли определять реализации, но теперь для интерфейсных методов можно добавить реализации по умолчанию. Мы также можем определить статические методы и методы по умолчанию, которые можно вызывать без объекта в интерфейсе. В основном интерфейсы используются для достижения множественного наследования и слабой связи в коде. Теперь, когда у нас есть четкое представление об интерфейсах, давайте посмотрим, что такое функциональный интерфейс и как он работает.

Что такое функциональный интерфейс?

Функциональный интерфейс также известен как интерфейс единого абстрактного метода (Single Abstract Method, SAM). Как следует из названия, он может иметь не более одного абстрактного метода. Функциональный интерфейс может иметь несколько статических методов и методов по умолчанию с реализацией, а также дополнительный абстрактный метод. Чтобы пометить интерфейс как функциональный, используется аннотация @FunctionalInterface. Она нужна, чтобы избежать ошибочного объявления дополнительных методов. Что делает функциональный интерфейс таким популярным, так это возможность использования лямбда-выражений для создания интерфейсов без использования анонимных и громоздких реализаций классов. Использование ключевого слова abstract в функциональных интерфейсах необязательно, поскольку методы, определенные внутри интерфейса, по умолчанию являются абстрактными.

Что такое лямбда-выражения?

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

(parameter list) -> lambda body
Оператор стрелки (->), который вы видите в коде, известен как лямбда-оператор. Например, если у нас есть следующий метод:

double getGoldenRatioValue() {
return 1.61803;
}
Используя лямбда-выражение, мы его можем записать так:

() -> 1.61803
Как видите, метод в лямбда-функции не имеет параметров, поэтому левая часть оператора пуста. Поскольку правая сторона определяет действие, то в данном примере она вернет значение золотого сечения: 1,61803. До появления Java 8 реализация интерфейсов или создание объектов внутреннего класса имели решающее значение, но с появлением Java 8 все, что нам теперь нужно делать, — это назначать лямбда-выражения функциональным интерфейсам.

Примеры функциональных интерфейсов

Для создания функциональных интерфейсов вы можете либо использовать аннотацию @FunctionalInterface, либо использовать предопределенные функциональные интерфейсы Java.

Пример 1

  • Сначала мы создадим отметку @FunctionalInterface и создадим интерфейс, под именем MyInterface, который вызывается абстрактным методом getGoldenRationValue().
  • Затем мы создадим публичный класс main для выполнения метода.
  • Чтобы использовать лямбда-выражение в функциональном интерфейсе, мы объявим ссылку на MyInterfaceDemo, а затем назначим лямбда-выражение этой ссылке.
  • Наконец, мы распечатаем значение золотого сечения, используя reference interface.

import java.lang.FunctionalInterface;

// Создание и маркировка функционального интерфейса
@FunctionalInterface

interface MyInterface {
// Это абстрактный метод
double getGoldenRatioValue();
}

public class Main {
public static void main( String[] args ) {

//декларируем ссылку на функциональный интерфейс
MyInterface ref;
//используем Lambda Expression
ref = () -> 1.61803;

System.out.println("Value of Golden Ratio = " + ref.getGoldenRatioValue());
}
}
Вывод:
Value of Golden Ratio = 1.61803

Пример 2

  • В этом примере мы собираемся использовать предопределенный функциональный интерфейс ToDoubleFunction, который принимает аргумент T и возвращает значение типа double в качестве вывода.
  • ToDoubleFuntion содержит абстрактный метод с именем applyasDouble().
  • И наконец, мы печатаем сообщение по всей длине, включая пробелы.

import java.util.function.ToDoubleFunction;
public class MyInterface2 {

public static void main(String[] args) {

ToDoubleFunction<String> length = x -> x.length();

System.out.println(length.applyAsDouble("This is an example of predefined functional interface."));
}
}
Вывод:
54.0

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

Теперь, когда мы знаем, как определять функциональные интерфейсы, давайте посмотрим, сколько существует предопределенных (встроенных) функциональных интерфейсов. Есть 4 основных типа функциональных интерфейсов, которые можно реализовать в различных ситуациях: Consumer, Predicate, Function и Supplier. Среди этих четырех интерфейсов Consumer, Function и Predicate имеют дополнительные функциональные интерфейсы. Вот список всех встроенных или предопределенных интерфейсов в Java. Примечание. T, U и R, упомянутые в таблице ниже, представляют собой тип первого аргумента (T), второго аргумента (U) и результата (R) операции соответственно.
Interface Type
Runnable
BiConsumer(T, U) T, U →
BiFunction(T, U, R) T, U → R
BinaryOperator T, T <→ R
BiPredicate<T, U> T, U → boolean
BooleanSupplier → boolean
Consumer T →
DoubleBinaryOperator double, double → double
DoubleConsumer double →
DoubleFunction double → R
DoublePredicate double → boolean
DoubleSupplier boolean →
DoubleToIntFunction double → int
DoubleToLongFunction double → long
DoubleUnaryOperator double → double
Function<T, R> T → R
IntBinaryOperator int → int
IntConsumer int →
IntFunction int → R
IntPredicate int → boolean
IntSupplier → int
IntToDoubleFunction int → double
IntToLongFunction int → long
IntUnaryOperator int → int
LongBinaryOperator long, long → long
LongConsumer long →
LongFunction long → R
LongPredicate long →
LongSupplier → long
LongToDoubleFunction long → double
LongToIntFunction long → int
LongUnaryOperator long → long
ObjDoubleConsumer T, double →
ObjIntConsumer T, int →
ObjLongConsumer T, long →
Predicate T → boolean
Supplier → T
ToDoubleBiFunction<T, U> T, U → double
ToDoubleFunction T → double
ToIntBiFunction<T, U> T, U → int
ToIntFunction T → int
ToLongBiFunction<T, U> T, U → long
ToLongFunction T → long
UnaryOperator T → T

Подводим итоги

Некоторые ключевые выводы, которые следует запомнить из этой публикации:
  • Интерфейс работает как механизм абстракции.
  • Функциональный интерфейс может иметь несколько статических методов и методов по умолчанию с реализацией, а также дополнительный абстрактный метод.
  • Методы, определенные внутри функционального интерфейса, по умолчанию являются абстрактными, поэтому использование ключевого слова abstract теперь необязательно.
  • Лямбда-выражение — это анонимный метод, который не выполняется сам по себе, а используется для реализации определенных методов функционального интерфейса.
  • Для создания функциональных интерфейсов вы можете либо использовать аннотацию @FunctionalInterface, либо использовать предопределенные функциональные интерфейсы Java.
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Игорь Попович Уровень 16
10 декабря 2022
Interface A1 { void method1(); String method2(String X); } Class A1 implements A { @Override public void method1(){} @Override public String method2(String X) { return x; } } Здесь наименование класса должно быть A1, а наименование интерфейса A Interface A {...} Class A1 implements A {...}