En tant que programmeur non-Java apprenant Java, je suis en train de lire sur les interfaces Supplier
et Consumer
pour le moment. Et je ne peux pas comprendre leur utilisation et leur signification. Quand et pourquoi utiliseriez-vous ces interfaces? Quelqu'un peut-il me donner un simple exemple de laïc? Je trouve les exemples de Doc pas assez succincts pour que je puisse comprendre.
C'est fournisseur:
public Integer getInteger() {
return new Random().nextInt();
}
C'est consommateur:
public void sum(Integer a, Integer b) {
System.out.println(a + b);
}
Donc, en termes simples, un fournisseur est une méthode qui renvoie une valeur (comme dans sa valeur de retour). Alors qu'un consommateur est une méthode qui consomme une certaine valeur (comme dans l'argument de méthode) et effectue certaines opérations sur celles-ci.
Ceux-ci vont se transformer en quelque chose comme ça:
// 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 ce qui concerne l'utilisation, l'exemple très basique serait: Stream#forEach(Consumer)
method. Il faut un consommateur, qui consomme l’élément du flux sur lequel vous effectuez une itération et effectue une action sur chacun d’eux. Probablement les imprimer.
Consumer<String> stringConsumer = (s) -> System.out.println(s.length());
Arrays.asList("ab", "abc", "a", "abcd").stream().forEach(stringConsumer);
La raison pour laquelle vous avez du mal à saisir la signification des interfaces fonctionnelles telles que celles de Java.util.function
est que les interfaces définies ici n'ont aucune signification! Ils sont présents principalement pour représenter structure, pas sémantique.
Ceci est atypique pour la plupart des API Java. L'API Java typique, telle qu'une classe ou une interface, a une signification et vous pouvez développer un modèle mental pour ce qu'elle représente et l'utiliser pour comprendre les opérations. Considérons Java.util.List
par exemple. Un List
est un conteneur d'autres objets. Ils ont une séquence et un index. Le nombre d'objets contenus dans la liste est renvoyé par size()
. Chaque objet a un index dans la plage 0..size-1 (inclus). L'objet à l'index i peut être récupéré en appelant list.get(i)
. Et ainsi de suite.
Les interfaces fonctionnelles dans Java.util.function
n'ont pas cette signification. Au lieu de cela, ce sont des interfaces qui représentent simplement la structure d'une fonction, telles que le nombre d'arguments, le nombre de valeurs renvoyées et (parfois) si un argument ou une valeur renvoyée est une primitive. Ainsi, nous avons quelque chose comme Function<T,R>
qui représente une fonction qui prend un seul argument de type T et renvoie une valeur de type R. C'est tout. Que fait cette fonction? Eh bien, il peut tout faire ... tant que cela prend un seul argument et renvoie une seule valeur. C'est pourquoi la spécification de Function<T,R>
est un peu plus que "Représente une fonction qui accepte un argument et produit un résultat".
Clairement, lorsque nous écrivons du code, cela a un sens, et ce sens doit venir de quelque part. Dans le cas des interfaces fonctionnelles, la signification provient du contexte dans lequel elles sont utilisées. L'interface Function<T,R>
n'a aucune signification en isolation. Cependant, dans l'API Java.util.Map<K,V>
, il existe les éléments suivants:
V computeIfAbsent(K key, Function<K,V> mappingFunction)
(les wildcards ont été supprimés pour des raisons de brièveté)
Ah, cette utilisation de Function
est une "fonction de mappage". Qu'est-ce que ça fait? Dans ce contexte, si key
n'est pas déjà présent dans la carte, la fonction de mappage est appelée et reçoit la clé. Elle doit produire une valeur et la paire clé-valeur résultante est insérée dans la carte.
Donc, vous ne pouvez pas regarder la spécification pour Function
(ni aucune autre interface fonctionnelle, d'ailleurs) et essayer de discerner ce qu'elles signifient. Vous devez regarder où elles sont utilisées dans d'autres API pour comprendre ce qu'elles veulent dire, et cette signification ne s'applique qu'à ce contexte.
Supplier
est une méthode qui ne prend aucun argument et renvoie une valeur. Son travail consiste littéralement à fournir une instance d'une classe attendue. Par exemple, chaque référence à une méthode 'getter' est une Supplier
public Integer getCount(){
return this.count;
}
Sa référence à la méthode d'instance myClass::getCount
est une instance de Supplier<Integer>
.
Consumer
est une méthode qui prend des arguments et ne renvoie rien. Il est invoqué pour ses effets secondaires. En termes Java, une Consumer
est un idiome pour une méthode void
. Les méthodes 'setter' sont un bon exemple:
public void setCount(int count){
this.count = count;
}
Sa référence à la méthode d'instance myClass::setCount
est une instance de Consumer<Integer>
et IntConsumer
.
Un Function<A,B>
est une méthode qui prend un argument d'un type et en retourne un autre. Ceci peut être appelé une "transformation". Le Function<A,B>
prend une A
et retourne une B
. Il est à noter que pour une valeur donnée de A
, la fonction doit toujours renvoyer une valeur spécifique de B
. A
et B
peuvent en fait être du même type, par exemple:
public Integer addTwo(int i){
return i+2;
}
Une référence de méthode de classe à un getter est également une fonction.
public Integer getCount(){
return this.count;
}
Sa référence à la méthode de classe MyClass::getCount
est une instance de Function<MyClass,Integer>
et ToIntFunction<MyClass>
.
Pourquoi les interfaces consommateur/fournisseur/autres fonctions sont-elles définies dans le package Java.util.function: Consommateur et fournisseur sont deux, parmi beaucoup d’autres, des interfaces fonctionnelles intégrées fournies dans Java 8. Les interfaces fonctionnelles construites fournissent un "modèle" prêt pour les interfaces fonctionnelles ayant des descripteurs de fonctions communs (signatures/définitions de méthodes fonctionnelles).
Disons que nous avons le devoir de convertir un type T en un autre type R. Si nous devions passer la fonction toute ainsi définie en tant que paramètre à une méthode, cette méthode devra définir une interface fonctionnelle dont La méthode fonctionnelle/abstraite prend en entrée le paramètre de type T et donne en sortie un paramètre de type R. Maintenant, il pourrait y avoir de nombreux scénarios comme celui-ci et le ou les programmeurs finiraient par définir plusieurs interfaces fonctionnelles pour leurs besoins. Pour éviter ce genre de scénario, faciliter la programmation et mettre en place un standard commun pour l'utilisation d'interfaces fonctionnelles, un ensemble d'interfaces fonctionnelles intégrées telles que prédicat, fonction, consommateur et fournisseur a été défini.
Que fait le consommateur: L'interface fonctionnelle du consommateur accepte une entrée, fait quelque chose avec cette entrée et ne donne aucune sortie. Sa définition est comme ça (de Java Source) -
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
Accept () est la méthode fonctionnelle\abstract qui prend une entrée et ne renvoie aucune sortie. Donc, si vous voulez entrer un Integer, faites-le avec aucune sortie, puis, au lieu de définir votre propre interface, utilisez une instance de Consumer.
Que fait le fournisseur: l'interface fonctionnelle du fournisseur ne prend aucune entrée mais renvoie une sortie. C'est défini comme ça (de Java Source) -
@FunctionalInterface
public interface Supplier<T> {
T get();
}
Partout où vous avez besoin d'une fonction qui retourne quelque chose, disons un entier, mais ne prend aucune sortie, utilisez une instance de fournisseur.
Si vous avez besoin de plus de clarté, ainsi que d’exemples d’utilisation, d’interfaces consommateur/fournisseur, vous pouvez vous reporter à mes articles de blog - http://www.javabrahman.com/Java-8/Java-8-Java- util-fonction-consommateur-tutoriel-avec-exemples/ethttp://www.javabrahman.com/Java-8/Java-8-Java-util-function-supplier-tutorial-with -exemples/
Voir mes réponses à ma question ici et aussi un autre ici , mais en bref, ces nouvelles interfaces fournissent convention et descriptivity à utiliser par tout le monde (+ chaîne enchaînée telle que .forEach(someMethod().andThen(otherMethod()))
Consumer: prend quelque chose, fait quelque chose, ne retourne rien: void accept(T t)
Fournisseur: Ne prend rien, retourne quelque chose: T get()
(inverse de Consumer, une méthode 'getter' universelle)
// Consumer: It takes something (a String) and does something (prints it)
List<Person> personList = getPersons();
personList.stream()
.map(Person::getName)
.forEach(System.out::println);
Fournisseur: code répétitif wrap, par ex. timing d'exécution du code
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;
}
}
En termes simples,
fournisseur fournira des données mais sans en consommer. En termes de programmation, une méthode qui ne prend aucun argument, mais renvoie une valeur. Il est utilisé pour générer de nouvelles valeurs.
http://codedestine.com/Java-8-supplier-interface/
le consommateur consommera des données et ne renverra aucune donnée. En termes de programmation, une méthode qui prend plusieurs arguments et ne renvoie aucune valeur.
Consommateur et fournisseur sont les interfaces fournies par Java. Le consommateur est utilisé pour parcourir les éléments de la liste et le fournisseur est utilisé pour les objets d'approvisionnement
vous pouvez facilement comprendre avec la démonstration du code.
Consommateur
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);
}
}
Fournisseur
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());
}
}