java - descargar - jdk 11
Java 8 Proveedor y consumidor explicación para el laico (7)
Como programador no Java que aprende Java, en este momento estoy leyendo sobre las interfaces de
Supplier
y
Consumer
.
Y no puedo entender mi uso y significado.
¿Cuándo y por qué usarías estas interfaces?
¿Puede alguien darme un ejemplo laico simple de esto ... Estoy encontrando que los ejemplos de Doc no son lo suficientemente sucintos para mi comprensión.
1. Significado
Vea mis respuestas a mi pregunta
here
y también otra
here
, 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()
(reverso del consumidor, 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: envolver 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;
}
}
¡La razón por la que tiene dificultades para comprender el significado de las interfaces funcionales como las de
java.util.function
es 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 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 él.
Considere
java.util.List
por ejemplo.
Una
List
es 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..size-1 (inclusive).
El objeto en el índice
i
se puede recuperar llamando a
list.get(i)
.
Etcétera.
Las interfaces funcionales en
java.util.function
no 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 de retorno y (a veces) si un argumento o valor de retorno es primitivo.
Por lo tanto, tenemos algo como
Function<T,R>
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 para la
Function<T,R>
es poco más que "Representa una función que acepta un argumento y produce un resultado".
Claramente, cuando estamos escribiendo código, tiene significado, y ese significado tiene que venir de algún lado.
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 API
java.util.Map<K,V>
, existe lo siguiente:
V computeIfAbsent(K key, Function<K,V> mappingFunction)
(comodines eliminados por brevedad)
Ah, este uso de
Function
es como una "función de mapeo".
Que hace eso
En este contexto, si la
key
no 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 ver dónde se usan en otras API para comprender lo que significan, y ese significado se aplica solo a ese contexto.
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
Puedes entenderlo fácilmente con la demostración de 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());
}
}
En términos laicos,
el 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 y 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.
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). Mientras que, un consumidor es un método que consume algún valor (como en el argumento del método), y realiza algunas operaciones en ellos.
Esos 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 más básico sería:
Stream#forEach(Consumer)
.
Se necesita un consumidor, que consume el elemento de la secuencia en la que está iterando, y realiza alguna acción en cada uno de ellos.
Probablemente imprimirlos.
Consumer<String> stringConsumer = (s) -> System.out.println(s.length());
Arrays.asList("ab", "abc", "a", "abcd").stream().forEach(stringConsumer);
Un
Supplier
es 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 un
Supplier
public Integer getCount(){
return this.count;
}
Su referencia de método de instancia
myClass::getCount
es una instancia de
Supplier<Integer>
.
Un
Consumer
es cualquier método que toma argumentos y no devuelve nada.
Se invoca por sus efectos secundarios.
En términos de Java, un
Consumer
es un modismo para un método
void
.
Los métodos ''setter'' son un buen ejemplo:
public void setCount(int count){
this.count = count;
}
Su referencia de método de instancia
myClass::setCount
es una instancia de
Consumer<Integer>
e
IntConsumer
.
Una
Function<A,B>
es cualquier método que toma un argumento de un tipo y devuelve otro.
Esto puede ser referido como una ''transformación''.
La
Function<A,B>
toma una
A
y devuelve una
B
Es notable que para un valor dado de
A
, la función siempre debe devolver un valor específico de
B
A
y
B
pueden ser del mismo tipo, como los siguientes:
public Integer addTwo(int i){
return i+2;
}
Su método de instancia hace referencia a
myClass:addTwo
es una
Function<Integer, Integer>
y una
ToIntFunction<Integer>
.
Una referencia de método de clase a un captador es otro ejemplo de una función.
public Integer getCount(){
return this.count;
}
Su referencia de método de clase
MyClass::getCount
es una instancia de
Function<MyClass,Integer>
y
ToIntFunction<MyClass>
.
¿Por qué se definen las interfaces funcionales Consumer / Supplier / other en el paquete java.util.function ? Consumer y Supplier son dos, entre muchas, de las interfaces funcionales incorporadas proporcionadas en Java 8. El propósito de todas estas interfaces funcionales incorporadas es para proporcionar una "plantilla" lista para interfaces funcionales que tengan descriptores de funciones comunes (firmas / definiciones de métodos funcionales).
Digamos que tenemos que convertir un tipo T a otro tipo R. Si tuviéramos que pasar cualquier función definida como este 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 proporciona 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, facilite la programación y traiga un estándar común en el uso de interfaces funcionales, se ha definido un conjunto de interfaces funcionales incorporadas como Predicate, Function, Consumer & Supplier.
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 número entero, haga algo con él sin salida y, en lugar de definir su propia interfaz, use una instancia de consumidor.
Qué hace el proveedor : la interfaz funcional del proveedor no toma ninguna entrada pero devuelve una salida. Se define así (desde Java Source):
@FunctionalInterface
public interface Supplier<T> {
T get();
}
Donde sea que necesite una función que devuelva algo, digamos un número entero, pero no tiene salida, use una instancia de Proveedor.
En caso de que se necesite más claridad, junto con el uso de ejemplo, 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/