[JAVA] Comment créer une méthode pratique qui utilise des génériques et une interface fonctionnelle

Créer une méthode pratique

Lorsque vous développez en équipe avec un grand nombre de personnes, le traitement que vous souhaitez faire en commun sort. Par exemple, les opérations de chaîne de caractères et les opérations de date sont utilisées dans diverses scènes, mais dans ce cas, je pense que vous utiliserez une bibliothèque pratique ou que vous créerez une classe avec des méthodes utiles.

S'il s'agit d'un processus pour une classe spécifique, il peut être créé dans une certaine mesure facilement, mais lors du développement avec un grand nombre de personnes, il y a une demande d'exécuter un processus commun pour différentes classes.

Quelque chose qui est pratique à utiliser à ce moment-là est "générique" ou "interface fonctionnelle". Même si vous connaissez ces deux choses, il peut être difficile pour certaines personnes de comprendre comment les utiliser réellement.

Donc, cette fois, je voudrais vous présenter comment l'utiliser réellement tout en suivant le processus de création d'une méthode pratique.

Qu'est-ce que les génériques (type générique)?

En le passant comme un paramètre à la définition du type de données, il est possible de prendre en charge un programme avec une structure similaire pour plusieurs types de données.

Par exemple, jusqu'au JDK1.4, lorsqu'il s'agissait de List, il n'y avait pas de spécification de type et tout pouvait être entré en tant qu'objet.

List list = new ArrayList();
list.add("string");
list.add(Integer.valueOf(100));

Si le type n'est pas limité et que vous ne souhaitez saisir que des caractères, la personne qui crée le programme doit faire attention. Après la sortie des génériques, il est devenu possible de spécifier le type, et il est devenu possible d'écrire comme suit.

List<String> list = new ArrayList<>();
list.add("string1");
list.add("string2");

En regardant les spécifications de l'API Java, elles sont répertoriées comme ** List \ <E > ** et ** ArrayList \ <E > **, respectivement. Cette partie ** E ** est appelée générique, et n'importe quel type peut être défini pour les programmes avec la même structure.

Qu'est-ce qu'une interface fonctionnelle?

Une simple représentation d'une interface fonctionnelle est une interface qui vous permet d'attribuer des «références de méthode» et des «expressions lambda» introduites dans Java 8.

Par exemple, getter et setter, qui sont souvent créés en Java, sont représentés par une interface fonctionnelle comme suit.

Méthode interface Méthode
getter Supplier<T> T get​()
setter Consumer<T> accept(T t)

Le fournisseur est une interface qui n'a aucun argument et renvoie n'importe quel type. Des compagnons similaires incluent IntSupplier, BooleanSupplier, etc., qui renvoient des primitives plutôt que des arbitraires.

Consumer est une interface qui prend des arguments et n'a pas de valeur de retour. Il existe également IntConsumer, DoubleConsumer, etc. qui transmettent des primitives à des pairs similaires plutôt que de manière arbitraire.

Créons une méthode pratique pour les tests unitaires

Pour ceux qui n'ont jamais utilisé de génériques ou d'interfaces fonctionnelles, l'explication ci-dessus peut être difficile. Par conséquent, je vais vous expliquer comment l'utiliser facilement tout en créant une méthode pratique.

Préparation

Disons que vous avez créé une classe d'étudiants. On suppose que la classe d'élèves a un numéro d'inscription scolaire, un nom d'élève et un âge, et le setter et le getter sont définis.

public class Student {
    /**Numéro d'étudiant*/
    private String code;

    /**Nom d'étudiant*/
    private String name;
    
    /**âge*/
    private int age;

    //... setter,abréviation getter...
}

Afin de préparer les données pour le test unitaire, nous allons créer trois étudiants en tant que données de test et les mettre dans une liste.

final Student student1 = new Student();
student1.setCode("S01001");
student1.setName("Yamada Taro");
student1.setAge(20);

final Student student2 = new Student();
student1.setCode("S02001");
student1.setName("Jiro Yamada");
student1.setAge(19);

final Student student3 = new Student();
student1.setCode("S03001");
student1.setName("Saburo Yamada");
student1.setAge(18);

final List<Student> students = new ArrayList<>();
students.add(student1);
students.add(student2);
students.add(student3);

Si c'est pour 3 personnes, je ne peux pas encore le voir, mais si ce nombre passe à 10 ou 20, ce sera un gros problème.

Créer une méthode qui simplifie la création d'une liste

Tout d'abord, j'ai créé une méthode qui simplifie la création de List.

public <T> List<T> createInstanceList(Supplier<T> supplier, int size) {
    return IntStream.range(0, size)
            .mapToObj(i -> supplier.get())
            .collect(toList());
}

J'expliquerai ce programme petit à petit.

public <T> List<T> createInstanceList(Supplier<T> supplier, int size) 

Tout d'abord, concernant la déclaration de la méthode, \ <T > et les génériques sont définis. Puisqu'il utilise des génériques, il est devenu une méthode qui peut être utilisée pour n'importe quelle classe.

Puisque le type de retour est ** List \ <T > **, une liste de n'importe quel type sera retournée.

Puisque le premier argument est déclaré ** Fournisseur \ <T > **, vous pouvez recevoir une interface juste pour renvoyer un type arbitraire comme mentionné dans l'introduction de Generics.

Le premier argument de chargement est ** int **, ce qui vous permet de spécifier la taille de la liste.

IntStream.range(0, size)

Vient ensuite la valeur à renvoyer. Tout d'abord, le flux est créé avec ** IntStream.range (0, size) **. Répétez de 0 à la taille -1 car vous utilisez la plage. Si la taille est 3, les nombres 0, 1, 2 sont répétés.

.mapToObj(i -> supplier.get())

IntStream a passé 0, 1, 2 plus tôt, mais je l'ignore et j'utilise ** supplier.get () **. Cela appelle la méthode get de l'interface de fonction passée en argument et renvoie le résultat.

.collect(toList());

Enfin, le nombre de fois que le nombre est répété (3 fois dans l'exemple) La valeur reçue de l'interface fonctionnelle est emballée dans une liste et renvoyée.

Appliquer la méthode de simplification de la liste

Comme certaines parties sont difficiles à expliquer, modifions le premier code pour voir comment cette méthode change réellement.

final List<Student> students = createInstanceList(Student::new, 3);
students.get(0).setCode("S01001");
students.get(0).setName("Yamada Taro");
students.get(0).setAge(20);
students.get(1).setCode("S02001");
students.get(1).setName("Jiro Yamada");
students.get(1).setAge(19);
students.get(2).setCode("S03001");
students.get(2).setName("Saburo Yamada");
students.get(2).setAge(18);

L'instanciation de l'étudiant et définie sur Liste ont disparu.

final List<Student> students = createInstanceList(Student::new, 3);

Cette première ligne crée une liste et une instance interne en même temps. ** Student :: new ** est dit être une ** référence de constructeur ** et renvoie une ** interface fonctionnelle ** qui renvoie le résultat de new Student ().

La référence du constructeur sera traitée comme un fournisseur et sera passée comme premier argument de la méthode créée précédemment. Le résultat de new Student () sera retourné par supplier.get () qui était dans la méthode précédente.

Créer une méthode pour définir une valeur pour un objet dans List

J'ai créé la méthode plus tôt et le code est plus court, mais la définition de la valeur est toujours compliquée. Par conséquent, j'écrirai le code suivant.

public <T, U> void setValues(List<T> obj, BiConsumer<T, U> biConsumer, U... values) {
    for (int i = 0; i < obj.size(); i++) {
        biConsumer.accept(obj.get(i), values[i]);
    }
}

J'expliquerai ce programme petit à petit.

public <T, U> void setValues(List<T> obj, BiConsumer<T, U> biConsumer, U... values)

Tout d'abord, concernant la déclaration de la méthode, ** \ <T, U > ** et les génériques sont définis. Contrairement à la première méthode, elle gère deux types arbitraires.

Étant donné que le type de retour est ** void **, aucune valeur n'est renvoyée.

Puisque le premier argument est ** List obj **, transmettez une liste de tout type pour lequel vous souhaitez définir une valeur.

Le deuxième argument est ** BiConsumer <T, U> biConsumer **. Cela sera expliqué plus tard.

Le troisième argument est ** U ... values **, et des arguments variables peuvent être passés. Avec cet argument, vous pouvez définir la valeur que vous souhaitez définir pour les objets de la variable List.

Appliquer la méthode pour l'ensemble de valeurs

Modifions le code pour voir comment il change lorsque nous utilisons réellement cette méthode.

final List<Student> students = createInstanceList(Student::new, 3);
setValues(students, Student::setCode, "S01001", "S02001", "S03001");
setValues(students, Student::setName, "Yamada Taro", "Jiro Yamada", "Saburo Yamada");
setValues(students, Student::setAge, 20, 19, 18);

Le code est beaucoup plus court et les perspectives sont meilleures.

Je souhaite définir une valeur pour le premier argument ** J'ai une liste d'étudiants **.

Nous transmettons une ** référence de méthode de définition ** comme deuxième argument. Cette référence de méthode est passée en tant que BiConsumer \ <T, U > pour la méthode que nous venons de créer et est appelée par biConsumer.accept (...).

Étant donné que le troisième argument et les suivants sont des ** arguments variables **, répertoriez les valeurs que vous souhaitez définir.

Référence de méthode de classe et référence de méthode d'instance

J'ai une question ici. La méthode setter doit normalement utiliser ** Consumer \ <T > ** car elle a un argument et aucune valeur de retour. Maintenant, expliquons brièvement pourquoi nous utilisons BiConsumer, une interface fonctionnelle qui prend deux arguments.

Par exemple, si vous utilisez Conumer \ <T > comme argument, vous pouvez créer le programme suivant.

public <T> void setValue(Consumer<T> consumer, T value) {
    consumer.accept(value);
}

Voici comment l'utiliser.

Student student = new Student();
setValue(student::setCode, "S01001");

Les différences par rapport à l'utilisation de BiConsumer sont les suivantes.

interface Référence de la méthode
BiConsumer<T, U> Student::setCode
Consumer<T> student::setCode

Lors de l'utilisation de BiConsumer, la référence de méthode de la classe est utilisée, et lors de l'utilisation de Consumer, ** la référence de méthode de l'instance ** est utilisée.

Puisque nous voulons définir la valeur de l'instance dans List cette fois, cela n'a pas de sens de transmettre une référence de méthode pour chaque instance de List. Par conséquent, je passe ** une référence de méthode de la classe ** et j'appelle setter pour chaque instance de la liste.

Résumé

Les deux méthodes suivantes ont été créées cette fois.

public <T> List<T> createInstanceList(Supplier<T> supplier, int size) {
    return IntStream.range(0, size)
            .mapToObj(i -> supplier.get())
            .collect(toList());
}

public <T, U> void setValues(List<T> obj, BiConsumer<T, U> biConsumer, U... values) {
    for (int i = 0; i < obj.size(); i++) {
        biConsumer.accept(obj.get(i), values[i]);
    }
}

Je travaille généralement sur le développement avec de nombreux étudiants. Puisqu'il existe de grandes différences de compétences, il est essentiel de pouvoir écrire autant que possible des programmes similaires et de créer des méthodes pratiques pour améliorer l'efficacité du développement.

Vous pouvez créer rapidement des méthodes simples et pratiques, mais plus vous essayez de créer des méthodes aussi génériques que possible, plus vous serez pratique si vous connaissez les génériques et les interfaces fonctionnelles présentées ici.

Recommended Posts

Comment créer une méthode pratique qui utilise des génériques et une interface fonctionnelle
Comment créer une méthode
Comment tester une méthode privée et la simuler partiellement en Java
Comment créer une classe qui hérite des informations de classe
Trouvez une valeur pratique pour avoir une méthode et en faire un ValueObject
Comment créer et exécuter des objets de classe Méthode, Proc, Méthode
Comment créer et lancer un Dockerfile pour Payara Micro
Comment créer un référentiel Maven pour 2020
[Swift5] Comment créer un écran de démarrage
[rails] Comment créer un modèle partiel
Une méthode simple et pratique pour HashMap
Comment créer un validateur qui n'autorise la saisie que dans un seul champ
Exécutable serveur avec Spring gradle Comment créer JAR et WAR
Comment faire fonctionner IGV en utilisant la communication par socket, et l'histoire de la création d'un Ruby Gem en utilisant cette méthode
Comment créer une base de données H2 n'importe où
[Rails] Comment créer un graphique à l'aide de lazy_high_charts
[Ruby] Comment utiliser la méthode gsub et la sous-méthode
Comment créer des pages pour le tableau "kaminari"
Comment créer un thème dans Liferay 7 / DXP
[1st] Comment créer un projet de framework Spring-MVC
Comment créer facilement un pull-down avec des rails
[Rails] Comment créer un bouton de partage Twitter
[Exemple de code Spring inclus] Comment créer un formulaire et comment obtenir plusieurs enregistrements
Comment créer un plugin Vagrant que vous avez appris lorsque vous avez forké et publié vagrant-mutagen
Comment créer un en-tête ou un pied de page une fois et l'utiliser sur une autre page
J'ai essayé d'utiliser Wercker pour créer et publier une image Docker qui lance GlassFish 5
Comment créer un environnement Java en seulement 3 secondes
Comment créer une URL JDBC (Oracle Database, Thin)
Comment créer un projet Spring Boot dans IntelliJ
Comment créer un URI de données (base64) en Java
Comment se moquer d'un appel de super méthode dans PowerMock
Comment convertir A en A et A en A en utilisant le produit logique et la somme en Java
[Offre d'abonnement Apple] Comment créer une signature d'offre promotionnelle
Comment créer docker-compose
Branchement conditionnel Java: comment créer et étudier des instructions de commutation
Comment créer une image de conteneur légère pour les applications Java
Comment créer un formulaire pour sélectionner une date dans le calendrier
Comment créer une partie d'espace réservé à utiliser dans la clause IN
Je veux appeler une méthode et compter le nombre
Créez une méthode qui peut récupérer des caractères à partir de n'importe quel emplacement
Créer une méthode pour renvoyer le taux de taxe en Java
Comment développer et enregistrer une application Sota en Java
Comment créer un portlet de générateur de services dans Liferay 7 / DXP
Comment laisser un commentaire
Créer une méthode java [Memo] [java11]
Comment insérer une vidéo
Comment créer un fichier jar et un fichier war à l'aide de la commande jar
[Rails 6] Comment créer un écran de saisie de formulaire dynamique à l'aide de cocoon
Comment POST JSON dans la méthode Java en utilisant OkHttp3 et la méthode en utilisant HttpUrlConnection-
Comment implémenter un travail qui utilise l'API Java dans JobScheduler
Comment créer un nouveau projet Gradle + Java + Jar dans Intellij 2016.03
Comment déployer une application qui référence un pot local à heroku
Comment charger un fichier de téléchargement Spring et afficher son contenu
Comment lire un fichier et le traiter comme une entrée standard
[Pratique à retenir !!!] Comment convertir du type LocalDate en chaîne de caractères et de la chaîne de caractères en type LocalDate
Comment stocker les informations saisies dans la zone de texte dans une variable de la méthode