Explicación del proveedor y consumidor de Java 8 para el profano

101

Como aprendizaje de Java programador no Java, estoy leyendo acerca Suppliery Consumerlas interfaces en el momento. Y no puedo entender su uso y significado. ¿Cuándo y por qué utilizaría estas interfaces? ¿Alguien puede darme un ejemplo simple de un profano de esto? Encuentro que los ejemplos de Doc no son lo suficientemente breves para mi comprensión.

james emanon
fuente
4
Cada página del API Doc tiene un enlace llamado "USE" en la parte superior en el que puede hacer clic Consumery Suppliertambién puede buscar el tutorial para Consumer...
Holger
7
Me encanta la respuesta de Stuart Marks. Y creo que la mayoría de las personas que respondieron a continuación no entendieron el punto. La cuestión no es "cómo" escribir Proveedores, Consumidores y Funciones. ¿Es "por qué" en el mundo le gustaría? Para una persona que no está acostumbrada a ellos, hacen que el código sea mucho más complejo. Pero el beneficio de usarlos no está claro.
anton1980
Por lo que puedo ver (y comparto su frustración con las descripciones tangenciales), es solo una forma hábil de abstraer tanto el tipo de objeto como el tratamiento del objeto de un objeto utilizado en un fragmento de código. Esto permite la aplicación de este mismo código a muchos tipos diferentes de objetos simplemente definiendo diferentes clases nuevas e inyectándolas en las interfaces de proveedor y consumidor. Entonces, en un sistema de registro policial, se usa el mismo código superficial para todos los sospechosos, pero la impresión final para cada uno depende de la clasificación de cada sospechoso, por ejemplo, 'ciudadano', 'mezquino', 'ladrón', 'delincuente', 'endurecido', etc.
Trunk

Respuestas:

95

Este es el proveedor:

public Integer getInteger() {
    return new Random().nextInt();
}

Este es el consumidor:

public void sum(Integer a, Integer b) {
    System.out.println(a + b);
}

Entonces, en términos simples, un proveedor es un método que devuelve algún valor (como en su valor de retorno). Considerando que, un consumidor es un método que consume algún valor (como en el argumento del método) y realiza algunas operaciones sobre ellos.

Aquellos se transformarán en algo como esto:

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

En cuanto al uso, el ejemplo muy básico sería: Stream#forEach(Consumer)método. Se necesita un consumidor, que consume el elemento de la secuencia sobre la que está iterando y realiza alguna acción en cada uno de ellos. Probablemente los imprima.

Consumer<String> stringConsumer = (s) -> System.out.println(s.length());
Arrays.asList("ab", "abc", "a", "abcd").stream().forEach(stringConsumer);
Rohit Jain
fuente
3
Entonces, ¿un proveedor es una forma de crear una instancia de un método que devuelve "algo"?
james emanon
3
@jamesemanon Exactamente. Podría ser una referencia de método o una lambda.
Rohit Jain
14
¿Cuál es el beneficio de esto en lugar de llamar al método directamente? ¿Es porque el Proveedor puede actuar como intermediario y transferir ese valor de "retorno"?
james emanon
1
El consumidor <Integer, Integer> no es válido. Un consumidor tiene un solo parámetro de tipo.
nascar
2
Pero, ¿POR QUÉ crear tal construcción? ¿Qué problema se resuelve al tenerlo en Java?
Trunk
178

La razón por la que tiene dificultades para comprender el significado de interfaces funcionales como las de java.util.functiones que las interfaces definidas aquí no tienen ningún significado. Están presentes principalmente para representar la estructura , no la semántica .

Esto es atípico para la mayoría de las API de Java. La API de Java típica, como una clase o interfaz, tiene significado, y puede desarrollar un modelo mental para lo que representa y usarlo para comprender las operaciones en ella. Considere, java.util.Listpor ejemplo. A Listes un contenedor de otros objetos. Tienen una secuencia y un índice. El número de objetos contenidos en la lista es devuelto por size(). Cada objeto tiene un índice en el rango 0..tamaño-1 (inclusive). El objeto en el índice i se puede recuperar llamando list.get(i). Etcétera.

Las interfaces funcionales en java.util.functionno tienen tal significado. En cambio, son interfaces que simplemente representan la estructura de una función, como el número de argumentos, el número de valores devueltos y (a veces) si un argumento o valor devuelto es una primitiva. Así tenemos algo así como Function<T,R>lo que representa una función que toma un solo argumento de tipo T y devuelve un valor de tipo R . Eso es. ¿Qué hace esa función? Bueno, puede hacer cualquier cosa ... siempre que tome un solo argumento y devuelva un solo valor. Es por eso que la especificación de Function<T,R>es poco más que "Representa una función que acepta un argumento y produce un resultado".

Claramente, cuando escribimos código, tiene un significado, y ese significado tiene que venir de alguna parte. En el caso de las interfaces funcionales, el significado proviene del contexto en el que se utilizan. La interfaz Function<T,R>no tiene significado de forma aislada. Sin embargo, en la java.util.Map<K,V>API, existe lo siguiente:

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

(comodines omitidos por brevedad)

Ah, este uso de Functiones como una "función de mapeo". ¿Qué hace eso? En este contexto, si aún keyno está presente en el mapa, se llama a la función de mapeo y se le entrega la clave y se espera que produzca un valor, y el par clave-valor resultante se inserta en el mapa.

Por lo tanto, no puede mirar la especificación de Function(o cualquiera de las otras interfaces funcionales, para el caso) e intentar discernir lo que significan. Debe observar dónde se usan en otras API para comprender lo que significan, y ese significado se aplica solo a ese contexto.

Stuart Marks
fuente
3
Básicamente, solo funciona como tipo
JGuo
Otra información útil puede ser que las interfaces funcionales pueden tener múltiples métodos implementados que pueden agregar comportamiento a su código
Jhon Mario Lotero
28

A Supplieres cualquier método que no toma argumentos y devuelve un valor. Su trabajo es, literalmente, proporcionar una instancia de una clase esperada. Por ejemplo, cada referencia a un método 'getter' es unaSupplier

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

Su referencia de método de instancia myClass::getCountes una instancia de Supplier<Integer>.

A Consumeres cualquier método que toma argumentos y no devuelve nada. Se invoca por sus efectos secundarios. En términos de Java, a Consumeres un modismo para un voidmétodo. Los métodos 'setter' son un buen ejemplo:

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

Su referencia de método de instancia myClass::setCountes una instancia de Consumer<Integer>y IntConsumer.

A Function<A,B>es cualquier método que toma un argumento de un tipo y devuelve otro. Esto puede denominarse "transformación". El Function<A,B>toma an Ay devuelve a B. Es de destacar que para un valor dado de A, la función siempre debe devolver un valor específico de B. Ay Bde hecho puede ser del mismo tipo, como el siguiente:

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

Su referencia de método de instancia myClass:addTwoes ay Function<Integer, Integer>a ToIntFunction<Integer>.

Una referencia de método de clase a un captador es otro ejemplo de función.

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

Su referencia de método de clase MyClass::getCountes una instancia de Function<MyClass,Integer>y ToIntFunction<MyClass>.

Steve K
fuente
15

¿Por qué se definen consumidor / proveedor / otras interfaces funcionales en el paquete java.util.function ? El consumidor y el proveedor son dos, entre muchas, de las interfaces funcionales integradas que se proporcionan en Java 8. El propósito de todas estas interfaces funcionales integradas es proporcionar una "plantilla" lista para interfaces funcionales que tengan descriptores de función comunes (firmas / definiciones de métodos funcionales).

Digamos que tenemos un requisito para convertir un tipo T a otro tipo R. Si tuviéramos que pasar cualquier función definida como esta como un parámetro a un método, entonces ese método necesitaría definir una Interfaz Funcional cuyo método funcional / abstracto toma parámetro de tipo T como entrada y da un parámetro de tipo R como salida. Ahora, podría haber muchos escenarios como este y los programadores terminarían definiendo múltiples interfaces funcionales para sus necesidades. Para evitar este tipo de escenario, facilitar la programación y traer un estándar común en el uso de interfaces funcionales, se ha definido un conjunto de interfaces funcionales integradas como Predicado, Función, Consumidor y Proveedor.

Qué hace el consumidor : la interfaz funcional del consumidor acepta una entrada, hace algo con esa entrada y no da ninguna salida. Su definición es así (de Java Source):

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

Aquí accept () es el método funcional \ abstracto que toma una entrada y no devuelve ninguna salida. Entonces, si desea ingresar un Integer, haga algo con él sin salida, entonces, en lugar de definir su propia interfaz, use una instancia de Consumer.

Qué hace el proveedor : la interfaz funcional del proveedor no toma ninguna entrada pero devuelve una salida. Se define así (de Java Source):

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

Siempre que necesite una función que devuelva algo, digamos un entero, pero no toma salida, use una instancia de Supplier.

En caso de que se necesite más claridad, junto con el uso de ejemplos, de las interfaces de consumidor y proveedor, puede consultar las publicaciones de mi blog en el mismo: http://www.javabrahman.com/java-8/java-8-java-util- function-consumer-tutorial-with-examples / y http://www.javabrahman.com/java-8/java-8-java-util-function-supplier-tutorial-with-examples/

Dhruv Rai Puri
fuente
12

1. Significado

Vea mis respuestas a mi pregunta aquí y también otra aquí , pero en resumen, estas nuevas interfaces proporcionan convenciones y descripciones para que todos las usen (+ encadenamiento de métodos funky como.forEach(someMethod().andThen(otherMethod()))

2. Diferencias

Consumidor : toma algo, hace algo, no devuelve nada:void accept(T t)

Proveedor: no toma nada, devuelve algo: T get()(al revés de Consumer, básicamente un método universal 'getter')

3. Uso

// Consumer: It takes something (a String) and does something (prints it) 
    List<Person> personList = getPersons();

     personList.stream()
                    .map(Person::getName)    
                    .forEach(System.out::println); 

Proveedor: envuelve código repetitivo, por ejemplo, tiempo de ejecución de código

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;
    }
}
Andrejs
fuente
0

En términos simples,

proveedor proporcionará datos pero sin consumir ningún dato. En términos de programación, un método que no toma ningún argumento pero devuelve un valor. Se utiliza para generar nuevos valores.

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

el consumidor consumirá datos pero no devolverá ningún dato. En términos de programación, un método que toma múltiples argumentos y no devuelve ningún valor.

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

lalitbhagtani
fuente
0

El consumidor y el proveedor son las interfaces proporcionadas por java. El consumidor se usa para iterar sobre los elementos de la lista y el proveedor se usa para los objetos de suministro.

se puede entender fácilmente con la demostración del código.

Consumidor

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

    }

}

Proveedor

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

}
Ankit Sood
fuente
0

La respuesta más simple puede ser:

Un consumidor puede verse como una función <T, nula>. Un proveedor puede verse como una función <Void, T>.

Yashwin Munsadwala
fuente