Что такое consumer java

Функциональные интерфейсы в Java 8 – это интерфейсы, которые содержат в себе только один абстрактный метод. Функциональные интерфейсы имеют тесную связь с лямбда выражениями и служат как основа для применения лямбда выражений в функциональном программировании на Java. Хотелось бы напомнить один нюанс — до появления Java 8 все методы в интерфейсе неявно считались абстрактными. С выходом JDK 8 появилось такое понятие как метод по умолчанию. Метод по умолчанию – это метод объявленный в интерфейсы, поведение которого предопределено, иначе говоря, метод уже имеет реализацию в интерфейсе. Давайте рассмотрим пример функционального интерфейса:

functionalInterface, в нашем примере является типичным функциональным интерфейсом, который содержит в себе один абстрактный метод – abstractMethod(). Аннотация @FunctionalInterface не обязательна, но я бы рекомендовал ее использовать, хотя бы для самоконтроля:

При наличии аннотации компилятор нам сообщит, что наш интерфейс больше не является функциональным, так как мы добавили в него второй абстрактный метод – abstractMethod1(). Немного практики никогда не повредит:

как вы думаете какой из этих трех интерфейсов можно назвать функциональным?

Правильный ответ – все три, в этом вы можете убедиться, добавив каждому из интерфейсов аннотацию @FunctionalInterface. Первый – не содержит в себе никаких методов, но наследует абстрактный метод от родительского интерфейса. Второй – содержит в себе один абстрактный метод, который переопределяет метод родительского интерфейса. Третий – содержит в себе метод по умолчанию, который абстрактным не является, но интерфейс так же наследует абстрактный метод, который наследуется от родительского интерфейса. Помните не важно сколько у вас методов по умолчанию или статичных методов в функциональном интерфейсе, главное, чтобы у вас был только один абстрактный метод.

Реализация функционального интерфейса, ничем не отличается от реализации обычного интерфейса:

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

Очередь за функциональным интерфейсом:

Вывод:
AudiA3
AudiA3
AudiA6

Метод printTest(), соответствует ли переданная характеристика машины истине(в нашем случае это наличие полного привода и бензиновый двигатель), если да – то метод выводит ее название. Как вы могли заметить, в метод для тестирования мы передавали лямбда выражения:

Первое выражение означает, вызов метода с параметром Car, который возвращает логическое выражение, которое в свою очередь является результатом вызова c.isFullDrive(). При вызове лямбда выражения Java полагается на его контекст. Если вы посмотрите на объявление метода printTest(), то в качестве второго параметра увидите функциональный интерфейс. Функциональный интерфейс содержит один метод test(), который принимает объект класса Car и возвращает логическое значение, на него лямбда выражение и проецируется. В самом же классе Car только два метода возвращают логическое значение, их мы и вызываем с помощью лямбд.

Обобщенные функциональные интерфейсы.

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

В класс Car была добавлена переменная для хранения информации об оборотах двигателя, а так же два метода гэттера для получения информации об оборотах и названии машины – getRPM() и getName(). Так же было добавлено два функциональных интерфейса GetName и GetRPM (не лучшие названия для интерфейсов, я знаю, но скоро мы от них избавимся). В главный класс программы были добавлены два метода для вывода на экран информации об оборотах и названия машины – printName() и printRPM(). Каждый из этих методов в качестве второго параметра принимает свой интерфейс. Вернемся к функциональным интерфейсам, если вы обратите внимание на методы в них, то заметите схожесть, отличие только в возвращаемом значении – String и Integer. Попробуем объединить эти интерфейсы, в этом нам помогут обобщения:

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

Предопределенные функциональные интерфейсы в Java 8.

Ранее мы всегда определяли собственные функциональные интерфейсы, но зачастую в этом нет необходимости, так как в JDK 8 представлены собственные функциональные интерфейсы, которые представлены в пакете java.util.function. Давайте рассмотрим некоторые из них:

Что такое consumer java. Смотреть фото Что такое consumer java. Смотреть картинку Что такое consumer java. Картинка про Что такое consumer java. Фото Что такое consumer java Функциональные интерфейсы в Java 8

С остальными функциональными интерфейсами, представленными в Java 8, вы можете ознакомиться на сайте Oracle. Настало время рассмотреть каждый функциональный интерфейс более подробно.

Supplier.

Попробуем применить этот функциональный интерфейс на практике. Создадим строку и выведем ее содержимое на экран:

Обратите внимание, для того чтобы начать использовать встроенные функциональные интерфейсы мы должны их импортировать import java.util.function*. Первой строчкой метода main() мы объявляем интерфейс Supplier с обобщенным типом String и присваиваем его промежуточной переменной sup. Основное предназначение этого интерфейса – создание новых объектов, давайте попробуем создать список с типом String:

В нашем примере используется вложенное обобщение, первое обобщение для Supplier – ArrayList и второе обобщение, оно же вложенное для ArrayList – String. Единственное, что делает Supplier из последнего примера, так это создает пустой строковый список.

Consumer и BiConsumer.

Отличие Consumer от BiConsumer только в количестве параметров, для BiConsumer параметров у метода accept два. Это характерно для всех интерфейсов, если видите приставку Bi значит в функциональном интерфейсе используется два параметра.

В примере Consumer выводит символьную строку, которую в него передали, на экран. Давайте переделаем предыдущий пример для BiConsumer:

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

На этот раз BiConsumer использует обобщения разных типов (String и Integer) и помогает нам заполнить HashMap двумя парами – ключ-значение.

Predicate и BiPredicate.

В метод test() передается один или два параметра, в зависимости от функционального интерфейса, а возвращается логическое значение true или false. Посмотрим, как это работает на практике, для начала проверим пустая строка или нет:

Выполнение этой программы выведет в консоль true. В лямбда выражение мы передаем строковое значение, к которому применяем метод isEmpty(), результат выполнения этого метода лямбда выражение возвращает обратно. Давайте теперь сравним две строки с помощью BiPredicate:

В этот раз мы передали в лямбда выражение две строки и вернули из него результат выполнения метода equals().

Function и BiFunction.

Попробуем посчитать количество символов в строке с помощью функционального интерфейса Function:

Обратите внимание, несмотря на то, что в лямбда выражение передается один параметр, в обобщениях мы все равно должны указать тип возвращаемого значения (в нашем случае Integer). Преобразуем строку из строчных букв, в строку из прописных букв:

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

Первых два обобщения в BiFunction определяют тип входных параметров, третье обобщение – возвращаемый тип.

UnaryOperator и BinaryOperator

Иначе говоря, использование этого интерфейса будет выглядеть как использования Function или BiFunction:

Воспользуемся функциональным интерфейсом UnaryOperator для реверса строки:

Настала очередь BinaryOperator, объединим две строки:

Обратите внимание, что, не смотря на три параметра (два входных и один для возвращаемого значения) в обобщении мы указываем только один тип – StringBuilder. Потому что, как говорилось ранее для функциональных интерфейсов UnaryOperator и BinaryOperator обобщенные типы должны совпадать и указывать три одинаковых типа обобщения просто не имеет смысла.
Хотелось бы отметить, что большинство выше описанных функциональных интерфейсов помимо абстрактных методов содержат в себе статичные и методы по умолчанию, которые были опущены при описании этих интерфейсов, но в ряде ситуаций они могут оказать колоссальную помощь, для того, чтобы ознакомиться с ними можете пройти по ссылке на официальное руководство Oracle по функциональным интерфейсам.

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

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

Что такое consumer java. Смотреть фото Что такое consumer java. Смотреть картинку Что такое consumer java. Картинка про Что такое consumer java. Фото Что такое consumer java Функциональные интерфейсы в Java 8 для примитивных типов

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

Что такое consumer java. Смотреть фото Что такое consumer java. Смотреть картинку Что такое consumer java. Картинка про Что такое consumer java. Фото Что такое consumer java Функциональные интерфейсы в Java 8 для примитивов

Источник

Новое в Java 8

Методы интерфейсов по умолчанию

Лямбда-выражения

Давайте начнем с простого примера: сортировка массива строк в предыдущих версиях языка.

Статический метод Collections.sort принимает список и компаратор, который используется для сортировки списка. Наверняка вам часто приходилось создавать анонимные компараторы для того чтобы передать их в метод.

Java 8 предоставляет гораздо более короткий синтаксис — лямбда-выражения, чтобы вам не приходилось тратить время на создание анонимных объектов:

Как видите, код гораздо короче и куда более читаем. И его можно сделать еще короче:

Компилятору известны типы параметров, поэтому их можно тоже опустить. Давайте посмотрим, как еще могут использовать лямбда-выражения.

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

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

Ссылки на методы и конструкторы

Предыдущий пример можно упростить, если использовать статические ссылки на методы:

Давайте посмотрим, как передавать ссылки на конструкторы. Сперва определим бин с несколькими конструкторами:

Затем определим интерфейс фабрики, которая будет использоваться для создания новых персон:

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

Области действия лямбд

Однако переменная num должна все равно оставаться неизменяемой. Следующий код не скомпилируется:

Запись в переменную num в пределах лямбда-выражения также запрещена.

Доступ к полям и статическим переменным

В отличии от локальных переменных, мы можем записывать значения в экземплярные поля класса и статические переменные внутри лямбда-выражений. Это поведение хорошо знакомо по анонимным объектам.

Доступ к методам интерфейсов по умолчанию

Внутри лямбда-выражений запрещено обращаться к методам по умолчанию. Следующий код не скомпилируется:

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

Однако в Java 8 также появилось много новых функциональных интерфейсов, которые призваны облегчить вам жизнь. Некоторые интерфейсы хорошо известны по библиотеке Google Guava. Даже если вы незнакомы с этой библиотекой, вам стоить взглянуть, как эти интерфейсы были дополнены некоторыми полезными методами расширений.

Предикаты
Функции
Поставщики

Поставщики (suppliers) предоставляют результат заданного типа. В отличии от функций, поставщики не принимают аргументов.

Потребители

Потребители (consumers) представляют собой операции, которые производятся на одним входным аргументом.

Компараторы

Компараторы хорошо известны по предыдущим версиям Java. Java 8 добавляет в интерфейс различные методы по умолчанию.

Опциональные значения

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

Опциональные значение — это по сути контейнер для значения, которое может быть равно null. Например, вам нужен метод, который возвращает какое-то значение, но иногда он должен возвращать пустое значение. Вместо того, чтобы возвращать null, в Java 8 вы можете вернуть опциональное значение.

Потоки

Сначала давайте посмотрим, как работать с потоком последовательно. Сперва создадим источник в виде списка строк:

Filter

Операция Filter принимает предикат, который фильтрует все элементы потока. Эта операция является промежуточной, т.е. позволяет нам вызвать другую операцию (например, forEach ) над результатом. ForEach принимает функцию, которая вызывается для каждого элемента в (уже отфильтрованном) поток. ForEach является конечной операцией. Она не возращает никакого значения, поэтому дальнейший вызов потоковых операций невозможен.

Sorted

Операция Sorted является промежуточной операцией, которая возвращает отсортированное представление потока. Элементы сортируются в обычном порядке, если вы не предоставили свой компаратор:

Помните, что sorted создает всего лишь отсортированное представление и не влияет на порядок элементов в исходной коллекции. Порядок строк в stringCollection остается нетронутым:

Match

Для проверки, удовлетворяет ли поток заданному предикату, используются различные операции сопоставления (match). Все операции сопоставления являются конечными и возвращают результат типа boolean.

Count
Reduce

Эта конечная операция производит свертку элементов потока по заданной функции. Результатом является опциональное значение.

Параллельные потоки

Как уже упоминалось выше, потоки могут быть последовательными и параллельными. Операции над последовательными потоками выполняются в одном потоке процессора, над параллельными — используя несколько потоков процессора.

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

Сперва создадим большой список из уникальных элементов:

Теперь измерим время сортировки этого списка.

Последовательная сортировка
Параллельная сортировка

Ассоциативные массивы

Как уже упоминалось, ассоциативные массивы (maps) не поддерживают потоки. Вместо этого ассоциативные массивы теперь поддерживают различные полезные методы, которые решают часто встречаемые задачи.

Этот код в особых комментариях не нуждается: putIfAbsent позволяет нам не писать дополнительные проверки на null; forEach принимает потребителя, который производит операцию над каждым элементом массива.

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

Затем мы узнаем, как удалить объект по ключу, только если этот объект ассоциирован с ключом:

Еще один полезный метод:

Объединить записи двух массивов? Легко:

В случае отсутствия ключа Merge создает новую пару ключ-значение. В противном случае — вызывает функцию объединения для существующего значения.

API для работы с датами

Clock
Часовые пояса
LocalTime

Тип LocalTime представляет собой время с учетом часового пояса, например, 10pm или 17:30:15. В следующем примере создаются два местных времени для часовых поясов, определенных выше. Затем оба времени сравниваются, и вычисляется разница между ними в часах и минутах.

Тип LocalTime содержит различные фабричные методы, которые упрощают создание новых экземпляров, а также парсинг строк.

LocalDate

Создание экземпляра LocalDate путем парсинга строки:

LocalDateTime

Форматирование даты-времени работает так же, как и форматирование даты или времени. Мы можем использовать библиотечные или свои собственные шаблоны.

Подробно о синтаксисе шаблонов можно почитать здесь.

Аннотации

Аннотации в Java 8 являются повторяемыми. Давайте сразу посмотрим пример, чтобы понять, что это такое.

Сперва мы определим аннотацию-обертку, которая содержит массив аннотаций:

Вариант 1: использовать аннотацию-контейнер (старый способ)

Вариант 2: использовать повторяемую аннотацию (новый способ)

Более того, аннотации в Java 8 можно использовать еще на двух элементах:

Вот и все

Полный исходный код статьи доступен на GitHub.

Источник

Understanding Java 8’s Consumer, Supplier, Predicate and Function

Functional programming in Java in a better way.

Что такое consumer java. Смотреть фото Что такое consumer java. Смотреть картинку Что такое consumer java. Картинка про Что такое consumer java. Фото Что такое consumer java

J ava has introduced functional programming support in Java release version 8. This specific release has also introduced several new concepts notably lambda expressions, method reference and a plethora of functional interfaces. While discussing functional interfaces, there are few functional interfaces namely Consumer, Supplier, Predicate and Functions are most crucial. In this article, we will talk about these interfaces.

Consumer

A Consumer is a functional interface that accepts a single input and returns no output. In layman’s language, as the name suggests the implementation of this interface consumes the input supplied to it. Consumer interface has two methods:

The accept method is the Single Abstract Method (SAM) which accepts a single argument of type T. Whereas, the other one andThen is a default method used for composition.

Following is an example of a consumer interface. We have created a consumer implementation that consumes a String and then prints it. The forEach method accepts consumer interface implementation.

In the following example, we demonstrate the usage of composing multiple consumer implementations to make a chain of consumers. In this specific example, we have created two consumers; one converts a list of items into upper case Strings and the other one prints the uppercased string.

Consumer interface has specific implementation types for integer, double and long types with IntConsumer, DoubleConsumer, and LongConsumer as shown below:

Supplier

A Supplier is a simple interface which indicates that this implementation is a supplier of results. This interface, however, does not enforce any restrictions that supplier implementation needs to return a different result on each invocation.

The supplier has only one method get() and does not have any other default and static methods.

The supplier interface has its primitive variants such as IntSupplier, DoubleSupplier and so on as shown below. Note that the method name is get() for the generic supplier interface. However, for the primitive variants, it is as per the primitive type.

One of the primary usage of this interface to enable deferred execution. This means delaying the execution until it is needed. For example, Optional class has a method named orElseGet. This method is triggered if optional does not have data. This is demonstrated below:

Predicate

A Predicate interface represents a boolean-valued-function of an argument. This is mainly used to filter data from a Java Stream. The filter method of a stream accepts a predicate to filter the data and return a new stream satisfying the predicate. A predicate has a test() method which accepts an argument and returns a boolean value.

In the above example, we have created a predicate which tests the names that start with S. This predicate is supplied to a stream.

Predicate also provides a few default and static method for composition and other purposes:

Following example demonstrates to use and method to compose predicates with multiple predicates.

Function

A Function interface is more of a generic one that takes one argument and produces a result. This has a Single Abstract Method (SAM) apply which accepts an argument of a type T and produces a result of type R. One of the common use cases of this interface is Stream.map method. This is shown as below:

Wrapping Up

The introduction of functional programming has introduced a new paradigm in Java language. And, Consumer, Supplier, Predicate and Function interfaces play a critical role in the way Java has enabled it. Mastering these interfaces and related primitive variants certainly help to write better functional code.

Источник

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

Термин функциональный интерфейс был введен в Java 8. Это интерфейс, который содержит только один абстрактный (не реализованный) метод. Может содержать стандартные и статические, которые имеют реализацию, в дополнение к одному нереализованному.

Вышеуказанное содержит только один метод, и этот метод не имеет реализации.

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

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

Реализация с помощью лямбда-выражения

Лямбда-выражение реализует единственный метод из интерфейса. Чтобы узнать, какой метод реализует лямбда-выражение, интерфейс может содержать только один не реализованный метод. Другими словами, он должен быть функциональным.

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

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

Function

Интерфейс Function interface(java.util.function.Function) является одним из самых центральных функциональных интерфейсов. Представляет функцию (метод), которая принимает один параметр и возвращает одно значение. Вот как выглядит определение:

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

Единственный метод, который необходимо реализовать для реализации интерфейса Function, – это apply(). Вот пример реализации функции:

В этой реализации функции реализован метод apply(), поэтому он принимает параметр Long в качестве параметра и возвращает Long. Вот пример использования вышеупомянутого класса AddThree:

Вы также можете реализовать Function с помощью лямбда-выражения:

Как видите, реализация Function теперь встроена в объявление переменной adderLambda, а не в отдельный класс. Это немного короче, плюс мы можем видеть непосредственно в приведенном выше коде, что он делает.

Predicate

Интерфейс Java Predicate, java.util.function.Predicate, представляет простую функцию, которая принимает одно значение в качестве параметра и возвращает true или false:

Интерфейс Predicate содержит больше методов, чем метод test(), но остальные являются стандартными или статическими, которые вам не нужно реализовывать.

Вы можете реализовать Predicate, используя класс, например так:

Вы также можете реализовать Predicate, используя лямбда-выражение:

Эта лямбда-реализация Predicate фактически делает то же самое, что и реализация выше, использующая класс.

UnaryOperator

Интерфейс Java UnaryOperator представляет операцию, которая принимает один параметр и возвращает параметр того же типа:

Интерфейс UnaryOperator может использоваться для представления операции, которая принимает конкретный объект в качестве параметра, изменяет этот объект и возвращает его снова – возможно, как часть цепочки обработки функционального потока.

BinaryOperator

BinaryOperator – это функциональный интерфейс, представляющий операцию, которая принимает два параметра и возвращает одно значение. Оба параметра и тип возвращаемого значения должны быть одного типа. Полезен при реализации функций, которые суммируют, вычитают, делят, умножают и т. д. Два элемента одного типа и возвращают третий элемент того же типа.

Supplier

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

Эта реализация Java Supplier возвращает новый экземпляр Integer со случайным значением от 0 до 1000.

Consumer

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

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *