Rechercher un élément
Nous connaissons désormais cette méthode de transformation de collections au design élégant, mais elle est inutile pour retrouver des éléments. Mais la méthode du filtre est née pour cela.
Nous souhaitons maintenant supprimer les noms commençant par N d'une liste de noms. Bien sûr, il se peut qu’il n’y en ait pas, et le résultat peut être un ensemble vide. Implémentons-le d’abord en utilisant l’ancienne méthode.
Copiez le code comme suit :
final List<String> startWithN = new ArrayList<String>();
pour(Nom de la chaîne : amis) {
if(nom.startsWith("N")) {
commenceAvecN.add(nom);
}
}
Écrire autant de code pour un événement aussi simple est assez verbeux. Nous créons d’abord une variable, puis l’initialisons dans une collection vide. Parcourez ensuite la collection d'origine et recherchez les noms commençant par la lettre spécifiée. S'il est trouvé, il est inséré dans la collection.
Utilisons la méthode filter pour reconstruire le code ci-dessus et voir à quel point il est puissant.
Copiez le code comme suit :
liste finale<String> startWithN =
amis.stream()
.filter(nom -> nom.startsWith("N"))
.collect(Collectors.toList());
La méthode filter reçoit une expression lambda qui renvoie une valeur booléenne. Si l'expression est évaluée comme vraie, cet élément dans le contexte d'exécution est ajouté au jeu de résultats ; sinon, il est ignoré ; Ce qui est finalement renvoyé est un Steam, qui contient uniquement les éléments dont l'expression renvoie vrai. Enfin, nous utilisons une méthode collect pour convertir la collection en liste - nous discuterons de cette méthode plus en détail dans Utilisation de la méthode collect et de la classe Collecters à la page 52.
Imprimons les éléments de cet ensemble de résultats :
Copiez le code comme suit :
System.out.println(String.format("%d noms trouvés", startWithN.size()));
Il ressort clairement du résultat que cette méthode a trouvé tous les éléments correspondants dans la collection.
Copiez le code comme suit :
J'ai trouvé 2 noms
La méthode filter, comme la méthode map, renvoie également un itérateur, mais c'est tout. La collection renvoyée par map a la même taille que la collection d'entrée, mais il est difficile de dire quel filtre renvoie. La plage de tailles de l'ensemble qu'il renvoie, de 0 au nombre d'éléments dans l'ensemble d'entrée. Contrairement à map, filter renvoie un sous-ensemble de l’ensemble d’entrée.
Jusqu'à présent, nous sommes très satisfaits de la simplicité du code apportée par les expressions lambda, mais si nous n'y prêtons pas attention, le problème de la redondance du code commencera lentement à s'aggraver. Discutons de ce problème ci-dessous.
Réutilisation des expressions lambda
Les expressions Lambda semblent très concises, mais en fait, il est facile de rendre le code redondant si vous n'y faites pas attention. La redondance entraînera une mauvaise qualité du code et des difficultés de maintenance ; si nous voulons apporter une modification, nous devons modifier plusieurs codes associés ensemble.
Éviter la redondance peut également nous aider à améliorer les performances. Le code concerné est concentré en un seul endroit, afin que nous puissions analyser ses performances puis optimiser le code ici, ce qui peut facilement améliorer les performances du code.
Voyons maintenant pourquoi l'utilisation d'expressions lambda peut facilement conduire à une redondance du code et réfléchissons à la manière de l'éviter.
Copiez le code comme suit :
liste finale<String> amis =
Arrays.asList("Brian", "Nate", "Neal", "Raju", "Sara", "Scott");
éditeurs List<String> finaux =
Arrays.asList("Brian", "Jackie", "John", "Mike");
liste finale<String> camarades =
Arrays.asList("Kate", "Ken", "Nick", "Paula", "Zach");
Nous voulons filtrer les noms commençant par une certaine lettre.
Nous voulons filtrer les noms commençant par une certaine lettre. Implémentons-le simplement en utilisant d'abord la méthode de filtrage.
Copiez le code comme suit :
décompte long finalFriendsStartN =
amis.stream()
.filter(nom -> nom.startsWith("N")).count();
décompte long finalEditorsStartN =
éditeurs.stream()
.filter(nom -> nom.startsWith("N")).count();
décompte long finalComradesStartN =
camarades.stream()
.filter(nom -> nom.startsWith("N")).count();
Les expressions Lambda donnent au code un aspect concis, mais elles apportent sans le savoir une redondance au code. Dans l'exemple ci-dessus, si nous voulons changer l'expression lambda, nous devons changer plusieurs endroits - ce qui n'est pas possible. Heureusement, nous pouvons attribuer des expressions lambda à des variables et les réutiliser comme des objets.
La méthode filter, le récepteur de l'expression lambda, reçoit une référence à l'interface fonctionnelle java.util.function.Predicate. Ici, le compilateur Java s'avère à nouveau utile. Il génère une implémentation de la méthode de test de Predicate en utilisant l'expression lambda spécifiée. Nous pouvons désormais demander plus explicitement au compilateur Java de générer cette méthode au lieu de la générer là où les paramètres sont définis. Dans l'exemple ci-dessus, nous pouvons stocker explicitement l'expression lambda dans une référence de type Predicate, puis transmettre cette référence à la méthode de filtrage, cela peut facilement éviter la redondance du code ;
Refactorisons le code précédent pour le rendre conforme au principe DRY. (Ne vous répétez pas - DRY - principe, veuillez vous référer au livre The Pragmatic Programmer: From Journeyman to Master [HT00]).
Copiez le code comme suit :
final Predicate<String> startWithN = nom -> nom.startsWith("N");
décompte long finalFriendsStartN =
amis.stream()
.filter(commenceAvecN)
.compter();
décompte long finalEditorsStartN =
éditeurs.stream()
.filter(commenceAvecN)
.compter();
décompte long finalComradesStartN =
camarades.stream()
.filter(commenceAvecN)
.compter();
Désormais, au lieu de réécrire l'expression lambda, nous l'écrivons une fois et la stockons dans une référence de type Predicate appelée startupWithN. Dans les trois appels de filtre suivants, le compilateur Java a vu l'expression lambda déguisée en Predicate, a souri et l'a acceptée en silence.
Cette variable nouvellement introduite élimine pour nous la redondance du code. Mais malheureusement, comme nous le verrons plus tard, l'ennemi reviendra bientôt pour se venger. Voyons quelles armes plus puissantes peuvent les détruire pour nous.