Пояснення для непрофесіонара Java 8 для постачальників та споживачів


101

Як програміст не-Java навчання Java, я читав про Supplierі Consumerінтерфейси в даний момент. І я не можу обернути голови навколо їх використання та значення. Коли і чому ви використовуєте ці інтерфейси? Чи може хтось навести мені простий непростий приклад цього ... Я вважаю приклади Doc недостатньо стислими для мого розуміння.


4
Кожна сторінка API Doc має посилання з написом «USE» у верхній частині , які ви можете натиснути на Consumerі SupplierВи можете також шукати підручник для Consumer...
Хольгер

7
Мені подобається відповідь Стюарта Маркса. І я думаю, що більшість людей, які відповіли нижче, пропустили суть. Питання не в тому, "як" писати Постачальники, Споживачі та Функції. Це "чому" у світі ти хотів би? Для людини, яка до них не звикла, вони роблять код набагато складнішим. Але користь від їх використання не ясна.
anton1980

Наскільки я бачу (і я поділяю ваше розчарування з дотичними описами), це просто пляжний спосіб абстрагування як об’єктного типу, так і обробки об’єкта від об’єкта, що використовується в фрагменті коду. Це дозволяє застосовувати цей самий код до багатьох різних типів об'єктів, просто визначаючи різні нові класи та вводячи їх в інтерфейси постачальника та споживача. Отже, в поліцейській системі обліку використовується той самий поверхневий код для всіх підозрюваних, але остаточний роздрук для кожного залежить від класифікації кожного підозрюваного, наприклад, "громадянин", "дрібний", "личинка", "злочинець", "загартований", та ін.
Магістраль

Відповіді:


95

Це постачальник:

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);

3
Отже, Постачальник - це спосіб створити екземпляр методу, який повертає "щось"?
James Emanon

3
@jamesemanon Точно. Це може бути посиланням на метод або лямбда.
Rohit Jain

14
Яка користь від цього, а не безпосередній виклик методу? Це тому, що Постачальник може діяти як посередник і передавати цю "повернуту" вартість?
James Emanon

1
Споживач <Integer, Integer> недійсний. Споживач має один параметр типу.
nascar

2
Але ЧОМУ створювати таку конструкцію? Яку проблему вирішує наявність на Java?
Багажник

177

Причина, з якою вам важко зрозуміти значення функціональних інтерфейсів, таких як ті java.util.function, що є, полягає в тому, що визначені тут інтерфейси не мають жодного значення! Вони присутні насамперед для представлення структури , а не семантики .

Це нетипово для більшості API Java. Типовий Java API, такий як клас або інтерфейс, має значення, і ви можете розробити розумову модель того, що вона представляє, і використовувати її для розуміння операцій над нею. Розглянемо java.util.Listдля прикладу. A List- контейнер інших об'єктів. Вони мають послідовність та індекс. Кількість об'єктів, що містяться у списку, повертається size(). Кожен об’єкт має індекс в діапазоні 0..розмір-1 (включно). Об'єкт з індексом i можна отримати за допомогою виклику list.get(i). І так далі.

Функціональні інтерфейси в java.util.functionне мають такого значення. Натомість вони є інтерфейсами, які просто представляють структуру функції, наприклад, кількість аргументів, кількість повернутих значень та (іноді), чи є аргумент чи повернене значення примітивним. Таким чином , ми маємо щось подібне , Function<T,R>яке представляє собою функцію , яка приймає один аргумент типу T і повертає значення типу R . Це воно. Що робить ця функція? Що ж, він може робити все, що завгодно, якщо він приймає один аргумент і повертає одне значення. Ось чому специфікація для Function<T,R>трохи більше, ніж "Представляє функцію, яка приймає один аргумент і дає результат".

Очевидно, що коли ми пишемо код, він має значення, і це значення має звідкись походити. У випадку функціональних інтерфейсів значення походить від контексту, в якому вони використовуються. Інтерфейс Function<T,R>не має окремого значення. Однак в java.util.Map<K,V>API є таке:

V computeIfAbsent(K key, Function<K,V> mappingFunction)

(узагальнюючі символи висловлені для стислості)

Ах, це використання Functionє як "функція відображення". Що це робить? У цьому контексті, якщо keyвона ще не присутня на карті, викликається функція відображення, якій вручається ключ і, як очікується, створить значення, а отримана пара ключ-значення вставляється на карту.

Отже, ви не можете дивитись на специфікацію Function(або будь-який інший функціональний інтерфейс), а також намагатися розпізнати, що вони означають. Ви повинні подивитися, де вони використовуються в інших API, щоб зрозуміти, що вони означають, і це значення стосується лише цього контексту.


3
Отже, в основному, це просто функція типу
JGuo

Ще однією корисною інформацією може бути те, що функціональні інтерфейси можуть мати декілька реалізованих методів, які можуть додати поведінку до вашого коду
Jhon Mario Lotero

28

A Supplier- це будь-який метод, який не бере аргументів і повертає значення. Його завдання буквально забезпечити екземпляр очікуваного класу. Наприклад, кожне посилання на метод 'getter' єSupplier

public Integer getCount(){
    return this.count;
}

Його посилання на метод екземпляра myClass::getCountє екземпляром Supplier<Integer>.

A Consumer- це будь-який метод, який бере аргументи і нічого не повертає. Його викликають через побічні ефекти. Якщо говорити термінами Java, a Consumer- це ідіома voidметоду. Хорошим прикладом є методи "setter":

public void setCount(int count){
    this.count = count;
}

Його посилання на метод екземпляра myClass::setCountє екземпляром Consumer<Integer>та IntConsumer.

A Function<A,B>- це будь-який метод, який приймає аргумент одного типу, а повертає інший. Це можна назвати "перетворенням". Function<A,B>Приймає Aі повертає B. Примітно те, що для заданого значення Aфункція завжди повинна повертати певне значення B. Aі Bнасправді може бути одного типу, наприклад, такого:

public Integer addTwo(int i){
    return i+2;
}

Його посиланням на метод екземпляра myClass:addTwoє a Function<Integer, Integer>та a ToIntFunction<Integer>.

Посилання на метод класу на геттер - ще один приклад функції.

public Integer getCount(){
    return this.count;
}

Його посилання на метод класу MyClass::getCountє екземпляром Function<MyClass,Integer>та ToIntFunction<MyClass>.


15

Чому споживач / постачальник / інші функціональні інтерфейси визначені в пакеті java.util.function : Споживач та постачальник - це два, серед багатьох, вбудованих функціональних інтерфейсів, що надаються в Java 8. Призначенням усіх цих вбудованих функціональних інтерфейсів є забезпечити готовий "шаблон" для функціональних інтерфейсів, що мають загальні дескриптори функцій (підписи / визначення функціонального методу).

Скажімо, у нас є необхідність перетворити тип T на інший тип R. Якби ми передали будь-яку функцію, визначену таким чином, як параметр, у метод, тоді цей метод повинен був би визначити функціональний інтерфейс, функціональний / абстрактний метод якого приймає параметр типу T як вхідні дані і дає параметр типу R як вихідні дані. Зараз таких сценаріїв може бути багато, і програміст (и) в кінцевому підсумку визначає безліч функціональних інтерфейсів для своїх потреб. Щоб уникнути такого роду сценаріїв, полегшити програмування та запровадити загальний стандарт використання функціональних інтерфейсів, було визначено набір вбудованих функціональних інтерфейсів, таких як предикат, функція, споживач та постачальник.

Що робить споживач : функціональний інтерфейс споживача приймає вхід, робить щось із цим входом і не дає жодного результату. Його визначення таке (з Java Source) -

@FunctionalInterface
public interface Consumer<T> {
 void accept(T t);
}

Тут accept () - це функціональний \ абстрактний метод, який приймає вхідні дані і не повертає вихідних даних. Отже, якщо ви хочете ввести ціле число, зробіть з ним щось без вихідних даних, тоді замість визначення власного інтерфейсу використовуйте екземпляр Consumer.

Що робить постачальник : функціональний інтерфейс постачальника не приймає жодного введення, а повертає результат. Його визначають так (з Java Source) -

@FunctionalInterface
public interface Supplier<T> {
  T get();
}

Скрізь, де вам потрібна функція, яка щось повертає, скажімо ціле число, але не отримує жодного результату, використовуйте екземпляр постачальника.

Якщо потрібна більша чіткість, поряд із прикладом використання, інтерфейсів споживачів та постачальників, тоді ви можете посилатись на мої публікації в блозі туди ж - http://www.javabrahman.com/java-8/java-8-java-util- function-consumer-tutorial-with-examples / і http://www.javabrahman.com/java-8/java-8-java-util-function-supplier-tutorial-with-examples/


12

1. Значення

Дивіться мої відповіді на моє запитання тут, а також інше тут , але коротше, ці нові інтерфейси забезпечують умовність та описовість для всіх (+ прикольний ланцюжок методів, такий як.forEach(someMethod().andThen(otherMethod()))

2. Відмінності

Споживач : Щось бере, щось робить, нічого не повертає:void accept(T t)

Постачальник: Нічого не бере, щось повертає: T get()(реверс від Споживача, в основному універсальний метод "отримання")

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;
    }
}

0

Якщо говорити неспеціалістами,

постачальник надаватиме дані, але не споживаючи жодних даних. У термінах програмування метод, який не приймає жодного аргументу, а повертає значення. Він використовується для генерації нових значень.

http://codedestine.com/java-8-supplier-interface/

споживач буде споживати дані, але не повертатиме жодних даних. У термінах програмування метод, який приймає кілька аргументів і не повертає жодного значення.

http://codedestine.com/java-8-consumer-interface/


0

Споживач та постачальник - це інтерфейси, що надаються 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());
    }

}

0

Найпростішою відповіддю може бути:

Споживача можна розглядати як функцію <T, Void>. Постачальник може розглядатися як функція <Порожнеча, T>.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.