Comme à peu près tout le monde, j'apprends toujours les subtilités (et les aime) de la nouvelle API Java 8 Streams. J'ai une question concernant l'utilisation des flux. Je vais vous donner un exemple simplifié.
Java Streams nous permet de prendre une Collection
et d’utiliser la méthode stream()
pour recevoir un flux de tous ses éléments. Il contient un certain nombre de méthodes utiles, telles que filter()
, map()
et forEach()
, qui nous permettent d’utiliser des opérations lambda sur le contenu.
J'ai un code qui ressemble à ceci (simplifié):
set.stream().filter(item -> item.qualify())
.map(item -> (Qualifier)item).forEach(item -> item.operate());
set.removeIf(item -> item.qualify());
L'idée est d'obtenir un mappage de tous les éléments de l'ensemble, correspondant à un certain qualificatif, puis de les utiliser. Après l'opération, ils ne servent à rien et doivent être supprimés de l'ensemble d'origine. Le code fonctionne bien, mais je ne peux m'empêcher de penser qu'il existe une opération dans Stream
qui pourrait le faire pour moi, en une seule ligne.
Si c'est dans les Javadocs, il se peut que je le néglige.
Est-ce que quelqu'un plus familier avec l'API voit quelque chose comme ça?
Vous pouvez le faire comme ça:
set.removeIf(item -> {
if (!item.qualify())
return false;
item.operate();
return true;
});
Si item.operate()
retourne toujours true
, vous pouvez le faire très succinctement.
set.removeIf(item -> item.qualify() && item.operate());
Cependant, je n’aime pas ces approches car il n’est pas clair tout de suite ce qui se passe. Personnellement, je continuerais à utiliser une boucle for
et une Iterator
pour cela.
for (Iterator<Item> i = set.iterator(); i.hasNext();) {
Item item = i.next();
if (item.qualify()) {
item.operate();
i.remove();
}
}
Dans une ligne non, mais vous pourriez peut-être utiliser le collecteur partitioningBy
:
Map<Boolean, Set<Item>> map =
set.stream()
.collect(partitioningBy(Item::qualify, toSet()));
map.get(true).forEach(i -> ((Qualifier)i).operate());
set = map.get(false);
Cela pourrait être plus efficace, car cela évite d'itérer l'ensemble deux fois, une pour filtrer le flux et une autre pour supprimer les éléments correspondants.
Sinon, je pense que votre approche est relativement bonne.
Il y a beaucoup d'approches. Si vous utilisez myList.remove (element) doit remplacer equals (). Deuxièmement, je préfère:
allList.removeIf(item -> item.getId().equals(elementToDelete.getId()));
Bonne chance et bon codage :)
Ce que vous voulez vraiment faire est de partitionner votre ensemble. Malheureusement, en Java 8, le partitionnement n’est possible que via la méthode "collect" du terminal. Vous vous retrouvez avec quelque chose comme ça:
// test data set
Set<Integer> set = ImmutableSet.of(1, 2, 3, 4, 5);
// predicate separating even and odd numbers
Predicate<Integer> evenNumber = n -> n % 2 == 0;
// initial set partitioned by the predicate
Map<Boolean, List<Integer>> partitioned = set.stream().collect(Collectors.partitioningBy(evenNumber));
// print even numbers
partitioned.get(true).forEach(System.out::println);
// do something else with the rest of the set (odd numbers)
doSomethingElse(partitioned.get(false))
Mis à jour:
Version Scala du code ci-dessus
val set = Set(1, 2, 3, 4, 5)
val partitioned = set.partition(_ % 2 == 0)
partitioned._1.foreach(println)
doSomethingElse(partitioned._2)`
si je comprends bien votre question:
set = set.stream().filter(item -> {
if (item.qualify()) {
((Qualifier) item).operate();
return false;
}
return true;
}).collect(Collectors.toSet());
Non, votre implémentation est probablement la plus simple. Vous pourriez faire quelque chose de profondément mal en modifiant l'état dans le prédicat removeIf
, mais veuillez ne pas le faire. D'un autre côté, il pourrait être raisonnable de passer à une implémentation impérative basée sur un itérateur, ce qui pourrait être plus approprié et efficace pour ce cas d'utilisation.
Après l'opération, ils ne servent à rien et doivent être supprimés de l'ensemble d'origine. Le code fonctionne bien, mais je ne peux pas m'empêcher de penser qu'il existe une opération dans Stream qui pourrait le faire pour moi, en une seule ligne.
Vous ne pouvez pas supprimer des éléments de la source du flux avec le flux. Depuis le Javadoc :
La plupart des opérations de flux acceptent des paramètres décrivant le comportement spécifié par l'utilisateur ..... Pour conserver le comportement correct, ces paramètres comportementaux:
- ne doit pas interférer (ils ne modifient pas la source du flux); et
- dans la plupart des cas, doivent être sans état (leur résultat ne devrait dépendre d'aucun état susceptible de changer au cours de l'exécution du pipeline de flux).
Je vois les préoccupations de Paul concernant la clarté lors de l'utilisation de flux, énoncées dans la réponse principale. Peut-être que l'ajout de la variable explicative clarifie un peu les intentions.
set.removeIf(item -> {
boolean removeItem=item.qualify();
if (removeItem){
item.operate();
}
return removeItem;
});