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

Функциональные интерфейсы в Java 8 → Consumer, Supplier, Predicate и Function. Что к чему и зачем нужны

Java представила поддержку функционального программирования в выпуске Java версии 8. Этот конкретный выпуск также представил несколько новых концепций, в частности лямбда-выражения, ссылки на методы и множество функциональных интерфейсов. При обсуждении последних, есть несколько функциональных интерфейсов, а именно Потребитель (Consumer), Поставщик (Supplier), Предикат (Predicat) и Функция (Function), которые являются наиболее важными. В этой статье мы о них и поговорим.

Consumer (потребитель)

Consumer — это функциональный интерфейс, который принимает один параметр на вход и не возвращает никаких выходных данных. На языке непрофессионала, как следует из названия, реализация этого интерфейса потребляет вводимые данные. Пользовательский интерфейс имеет два метода:

void accept(T t); default Consumer andThen(Consumer after);

Метод accept является единым абстрактным методом (SAM), который принимает один аргумент типа T. Тогда как другой метод andThen является методом по умолчанию и используется для композиции.

Ниже приведен пример интерфейса consumer. Мы создали потребительскую реализацию, которая использует строку, а затем просто выводит ее на экран. Метод forEach принимает реализацию потребительского интерфейса.

public void whenNamesPresentConsumeAll() < ConsumerprintConsumer = t -> System.out.println(t); Stream cities = Stream.of("Sydney", "Dhaka", "New York", "London"); cities.forEach(printConsumer); >

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

public void whenNamesPresentUseBothConsumer() < Listcities = Arrays.asList("Sydney", "Dhaka", "London"); Consumer upperCaseConsumer = list -> < for(int i=0; i< list.size(); i++)< list.set(i, list.get(i).toUpperCase()); >>; Consumer printConsumer = list -> list.stream() .forEach(System.out::println); upperCaseConsumer.andThen(printConsumer).accept(cities); >

Интерфейс Consumer имеет специфические типы реализаций для типов integer, double и long -> IntConsumer, DoubleConsumer и LongConsumer, как показано ниже:

IntConsumer void accept(int x); DoubleConsumer void accept(double x); LongConsumer void accept(long x);

Supplier (поставщик)

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

У поставщика есть только один метод get() и нет никаких других методов по умолчанию или статических методов.

public void supplier() < SupplierdoubleSupplier1 = () -> Math.random(); DoubleSupplier doubleSupplier2 = Math::random; System.out.println(doubleSupplier1.get()); System.out.println(doubleSupplier2.getAsDouble()); >

Интерфейс поставщик имеет свои примитивные варианты, такие как IntSupplier, DoubleSupplier и т. д., как показано ниже. Обратите внимание, что имя метода — get() используется для универсального интерфейса поставщика. Однако для примитивных вариантов этот метод соответствует примитивному типу.

IntSupplier int getAsInt(); DoubleSupplier double getAsDouble(); LongSupplier long getAsLong(); BooleanSupplier boolean getAsBoolean();

Одно из основных применений этого интерфейса это использование для включения отложенного выполнения. Это означает отсрочку выполнения до тех пор, пока оно не понадобится. Например, в классе Optional есть метод orElseGet. Этот метод срабатывает, если у option нет данных. Это показано ниже:

public void supplierWithOptional() < SupplierdoubleSupplier = () -> Math.random(); Optional optionalDouble = Optional.empty(); System.out.println(optionalDouble.orElseGet(doubleSupplier)); >

Predicate (предикат)

Интерфейс Predicate представляет собой логическую функцию аргумента. Он в основном используется для фильтрации данных из потока (stream) Java. Метод фильтра потока принимает предикат для фильтрации данных и возврата нового потока, удовлетворяющего предикату. У предиката есть метод test(), который принимает аргумент и возвращает логическое значение.

public void testPredicate() < Listnames = Arrays.asList("Smith", "Samueal", "Catley", "Sie"); Predicate nameStartsWithS = str -> str.startsWith("S"); names.stream().filter(nameStartsWithS).forEach(System.out::println); >

В приведенном выше примере мы создали предикат, который проверяет имена, начинающиеся с S. Этот предикат передается потоку.

Predicate также предоставляет несколько стандартных и статических методов для композиции и других целей:

default Predicate and(Predicate other); default Predicate or(Predicate other); static Predicate isEquals(Object targetRef); default Predicate negate();

В следующем примере демонстрируется использование и метод для составления цепочки предикатов.

public void testPredicateAndComposition() < Listnames = Arrays.asList("Smith", "Samueal", "Catley", "Sie"); Predicate startPredicate = str -> str.startsWith("S"); Predicate lengthPredicate = str -> str.length() >= 5; names.stream() .filter(startPredicate.and(lengthPredicate)) .forEach(System.out::println); >

Function (функция)

Интерфейс Function — это более общий интерфейс, который принимает один аргумент и выдает результат. В нем применяется единый абстрактный метод (SAM), который принимает аргумент типа T и выдает результат типа R. Одним из распространенных вариантов использования этого интерфейса является метод Stream.map. Пример использования показан ниже:

public void testFunctions() < Listnames = Arrays.asList("Smith", "Gourav", "John", "Catania"); Function nameMappingFunction = String::length; List nameLength = names.stream() .map(nameMappingFunction).collect(Collectors.toList()); System.out.println(nameLength); >

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

Введение функционального программирования представило новую парадигму языка Java. И интерфейсы Consumer, Supplier, Predicate и Function играют решающую роль в том, как это реализовано в Java. Освоение этих интерфейсов и связанных с ними примитивных вариантов, безусловно, помогает писать более качественный функциональный код.

Источник

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

Java-университет

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

Источник: DZone Вашему вниманию представлен обзор функциональных интерфейсов в Java: предназначение, примеры, лямбда-выражения и список предустановленных интерфейсов. Будучи объектно-ориентированным языком программирования, 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()

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

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

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

Пример 1

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

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

Теперь, когда мы знаем, как определять функциональные интерфейсы, давайте посмотрим, сколько существует предопределенных (встроенных) функциональных интерфейсов. Есть 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
BiPredicate 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
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 → double
ToDoubleFunction T → double
ToIntBiFunction T, U → int
ToIntFunction T → int
ToLongBiFunction T, U → long
ToLongFunction T → long
UnaryOperator T → T

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

  • Интерфейс работает как механизм абстракции.
  • Функциональный интерфейс может иметь несколько статических методов и методов по умолчанию с реализацией, а также дополнительный абстрактный метод.
  • Методы, определенные внутри функционального интерфейса, по умолчанию являются абстрактными, поэтому использование ключевого слова abstract теперь необязательно.
  • Лямбда-выражение — это анонимный метод, который не выполняется сам по себе, а используется для реализации определенных методов функционального интерфейса.
  • Для создания функциональных интерфейсов вы можете либо использовать аннотацию @FunctionalInterface , либо использовать предопределенные функциональные интерфейсы Java.

Источник

Читайте также:  Button templates in css
Оцените статью