Как программист, не являющийся Java-программистом, изучающий Java, я читаю о интерфейсах Supplier
и Consumer
на данный момент. И я не могу склонить голову вокруг их использования и смысла. Когда и почему вы будете использовать эти интерфейсы? Может ли кто-нибудь дать мне простой пример этого человека... Я нахожу примеры Doc, недостаточно сжатые для понимания.
Java 8 Поставщик и потребительское объяснение для непрофессионала
Ответ 1
Это поставщик:
public Integer getInteger() {
return new Random().nextInt();
}
Это потребитель:
public void sum(Integer a, Integer b) {
System.out.println(a + b);
}
Таким образом, в условиях непрофессионала поставщик - это метод, который возвращает некоторое значение (как в возвращаемом значении). Принимая во внимание, что потребитель - это метод, который потребляет некоторое значение (как в аргументе метода) и выполняет некоторые операции над ними.
Они преобразуются в нечто подобное:
// new operator itself is a supplier, of the reference to the newly created object
Supplier<List<String>> listSupplier = ArrayList::new;
Consumer<String> printConsumer = a1 -> System.out.println(a1);
BiConsumer<Integer, Integer> sumConsumer = (a1, a2) -> System.out.println(a1 + a2);
Что касается использования, самым простым примером может быть: Stream#forEach(Consumer)
. Он берет Потребителя, который потребляет элемент из потока, который вы выполняете, и выполняет некоторые действия для каждого из них. Возможно, напечатайте их.
Consumer<String> stringConsumer = (s) -> System.out.println(s.length());
Arrays.asList("ab", "abc", "a", "abcd").stream().forEach(stringConsumer);
Ответ 2
Причина, по которой вы испытываете трудности с пониманием функциональных интерфейсов, например, в java.util.function
, состоит в том, что указанные здесь интерфейсы не имеют никакого значения! Они присутствуют прежде всего для представления структуры, а не семантики.
Это не типично для большинства API Java. Обычный Java API, такой как класс или интерфейс, имеет смысл, и вы можете разработать ментальную модель для того, что она представляет, и использовать ее для понимания операций на ней. Рассмотрим, например, java.util.List
. A List
- контейнер других объектов. У них есть последовательность и индекс. Количество объектов, содержащихся в списке, возвращается size()
. Каждый объект имеет индекс в диапазоне 0..размер-1 (включительно). Объект с индексом я можно получить, вызвав list.get(i)
. И так далее.
Функциональные интерфейсы в java.util.function
не имеют такого значения. Вместо этого они являются интерфейсами, которые просто представляют структуру функции, такую как количество аргументов, количество возвращаемых значений и (иногда), является ли аргумент или возвращаемое значение примитивным. Таким образом, мы имеем что-то вроде Function<T,R>
, которое представляет собой функцию, которая принимает один аргумент типа T и возвращает значение типа R. Это. Что делает эта функция? Ну, он может делать все... до тех пор, пока он принимает один аргумент и возвращает одно значение. Поэтому спецификация для Function<T,R>
немного больше, чем "Представляет функцию, которая принимает один аргумент и производит результат".
Ясно, что когда мы пишем код, у него есть смысл, и этот смысл должен произойти откуда-то. В случае функциональных интерфейсов смысл исходит из контекста, в котором они используются. Интерфейс Function<T,R>
не имеет смысла в изоляции. Однако в API java.util.Map<K,V>
существует следующее:
V computeIfAbsent(K key, Function<K,V> mappingFunction)
(подстановочные знаки для краткости)
Ah, это использование Function
является "функцией отображения". Что это делает? В этом контексте, если key
еще не присутствует на карте, вызывается функция отображения и передается ключ, и ожидается, что она выдает значение, а полученная пара ключей и значений вставлена в карту.
Таким образом, вы не можете посмотреть спецификацию для Function
(или любого другого функционального интерфейса, если на то пошло) и попытаться понять, что они означают. Вы должны посмотреть, где они используются в других API, чтобы понять, что они означают, и это значение относится только к этому контексту.
Ответ 3
Supplier
- это любой метод, который не принимает аргументов и возвращает значение. Его работа состоит в том, чтобы буквально предоставить экземпляр ожидаемого класса. Например, каждая ссылка на метод "получателя" является Supplier
public Integer getCount(){
return this.count;
}
Ссылка на метод экземпляра myClass::getCount
является экземпляром Supplier<Integer>
.
Consumer
- это любой метод, который принимает аргументы и ничего не возвращает. Это вызвано для его побочных эффектов. В терминах Java Consumer
- это идиома для метода void
. Методы 'setter' являются хорошим примером:
public void setCount(int count){
this.count = count;
}
Ссылка на метод экземпляра myClass::setCount
является экземпляром Consumer<Integer>
и IntConsumer
.
Function<A,B>
- это любой метод, который принимает аргумент одного типа и возвращает другой. Это можно назвать "преобразованием". Function<A,B>
принимает A
и возвращает B
Следует отметить, что для данного значения A
функция всегда должна возвращать определенное значение B
A
и B
на самом деле могут быть одного типа, такие как следующие:
public Integer addTwo(int i){
return i+2;
}
Ссылка на метод экземпляра myClass:addTwo
представляет собой Function<Integer, Integer>
и функцию ToIntFunction<Integer>
.
Ссылка на метод класса для получения является еще одним примером функции.
public Integer getCount(){
return this.count;
}
Ссылка на метод класса MyClass::getCount
является экземпляром Function<MyClass,Integer>
и ToIntFunction<MyClass>
.
Ответ 4
Почему Потребитель/Поставщик/другие функциональные интерфейсы определены в пакете java.util.function: Потребитель и Поставщик - это два, среди многих, встроенных функциональных интерфейсов, представленных в Java 8. Назначение всех этих встроенных функциональных интерфейсов состоит в том, чтобы предоставить готовый "шаблон" для функциональных интерфейсов, имеющих общие дескрипторы функций (сигнатуры/определения функциональных методов).
Допустим, у нас есть требование для преобразования типа T в другой тип R. Если бы мы передали в метод любую функцию, определенную как этот параметр, то этот метод должен был бы определить функциональный интерфейс, чей функциональный/абстрактный метод принимает параметр типа T в качестве входных данных и дает параметр типа R в качестве выходных данных. Теперь таких сценариев может быть много, и программист в конечном итоге определит несколько функциональных интерфейсов для своих нужд. Чтобы избежать такого сценария, упростить программирование и ввести общий стандарт использования функциональных интерфейсов, был определен набор встроенных функциональных интерфейсов, таких как Predicate, Function, Consumer & Supplier.
Что делает Consumer: функциональный интерфейс Consumer принимает входные данные, что-то делает с этим входом и не выдает никаких выходных данных. Его определение таково (из Java Source) -
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
Здесь accept() - это функциональный\абстрактный метод, который принимает входные данные и не возвращает никаких выходных данных. Итак, если вы хотите ввести целое число, сделайте что-нибудь с ним без вывода, тогда вместо определения собственного интерфейса используйте экземпляр Consumer.
Что делает Поставщик: Функциональный интерфейс Поставщика не принимает никаких входных данных, а возвращает выходные данные. Это определено так (из Java Source) -
@FunctionalInterface
public interface Supplier<T> {
T get();
}
Везде, где вам нужна функция, которая возвращает что-то, скажем, Integer, но не выводит, используйте экземпляр поставщика.
В случае, если необходима дополнительная ясность, а также пример использования интерфейсов Consumer & Supplier, вы можете ссылаться на мои сообщения в блоге по этому же адресу - http://www.javabrahman.com/java-8/java-8-java-util- функция-потребитель-учебник с примерами / и http://www.javabrahman.com/java-8/java-8-java-util-function-supplier-tutorial-with-examples/
Ответ 5
1. Значение
Посмотрите мои ответы на мой вопрос здесь, а также еще один здесь, но вкратце эти новые интерфейсы предоставляют условное и описательность для всех, кто может использовать (+ funky method chaining, например .forEach(someMethod().andThen(otherMethod()))
2. Различия
Потребитель: принимает что-то, что-то делает, ничего не возвращает: void accept(T t)
Поставщик: ничего не принимает, возвращает что-то: T get()
(обратная сторона Потребителя, в основном универсальный метод "getter" )
3. Использование
// Consumer: It takes something (a String) and does something (prints it)
List<Person> personList = getPersons();
personList.stream()
.map(Person::getName)
.forEach(System.out::println);
Поставщик: повторяйте повторяющийся код, например. время выполнения кода
public class SupplierExample {
public static void main(String[] args) {
// Imagine a class Calculate with some methods
Double result1 = timeMe(Calculate::doHeavyComputation);
Double result2 = timeMe(Calculate::doMoreComputation);
}
private static Double timeMe(Supplier<Double> code) {
Instant start = Instant.now();
// Supplier method .get() just invokes whatever it is passed
Double result = code.get();
Instant end = Instant.now();
Duration elapsed = Duration.between(start,end);
System.out.println("Computation took:" + elapsed.toMillis());
return result;
}
}
Ответ 6
Поставщик и потребитель - это функциональные интерфейсы (т.е. интерфейс с одним методом). Они были представлены на Java 8 наряду с другими конструкциями функционального программирования, используемыми для пакетной обработки потоков информации.
У поставщика есть один метод с именем get
, который возвращает значение
// functional interface
public interface Supplier {
// one method
public void get();
}
У потребителя есть один метод с именем accept
, который добавляет значение
// functional interface
public interface Consumer {
// one method
public void accept();
}
Пример, который реализует интерфейсы Поставщика и Потребителя:
import java.util.function.Supplier;
import java.util.function.Consumer;
public class SupplierConsumerExample {
public static void main(String[] args) {
Supplier<String> supplier = () -> {
return "s1";
};
String s1 = supplier.get();
System.out.println(s1); // output: "s1"
Consumer<String> consumer = (c) -> {
System.out.println(c); // output: "c1", "c2"
};
consumer.accept("c1");
consumer.accept("c2");
}
}
Ответ 7
В терминах Laymen
поставщик будет поставлять данные, но не потребляя никаких данных. В терминах программирования используется метод, который не принимает никаких аргументов, а возвращает значение. Он используется для генерации новых значений.
http://codedestine.com/java-8-supplier-interface/
потребитель будет потреблять данные и не возвращать данные. В терминах программирования используется метод, который принимает несколько аргументов и не возвращает никакого значения.
Ответ 8
Потребитель и поставщик - это интерфейсы, предоставляемые java. Потребитель использует для итерации над элементами списка, а поставщик используется для объекта поставки
вы можете легко понять с демонстрацией кода.
Потребитель
package com.java.java8;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
/**
* The Class ConsumerDemo.
*
* @author Ankit Sood Apr 20, 2017
*/
public class ConsumerDemo {
/**
* The main method.
*
* @param args
* the arguments
*/
public static void main(String[] args) {
List<String> str = new ArrayList<>();
str.add("DEMO");
str.add("DEMO2");
str.add("DEMO3");
/* Consumer is use for iterate over the List */
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String t) {
/* Print list element on consile */
System.out.println(t);
}
};
str.forEach(consumer);
}
}
Поставщик
package com.java.java8;
import java.util.function.Supplier;
/**
* The Class SupplierDemo.
*
* @author Ankit Sood Apr 20, 2017
*/
public class SupplierDemo {
/**
* The main method.
*
* @param args
* the arguments
*/
public static void main(String[] args) {
getValue(() -> "Output1");
getValue(() -> "OutPut2");
}
/**
* Gets the value.
*
* @param supplier
* the supplier
* @return the value
*/
public static void getValue(Supplier<?> supplier) {
System.out.println(supplier.get());
}
}