Disons que nous avons ce morceau de code ennuyeux que nous avons tous dû utiliser:
ArrayList<Long> ids = new ArrayList<Long>();
for (MyObj obj : myList){
ids.add(obj.getId());
}
Après être passé à Java 8, mon IDE me dit que je peux remplacer ce code par collect call
, et il génère automatiquement:
ArrayList<Long> ids = myList.stream().map(MyObj::getId).collect(Collectors.toList());
Cependant, cela me donne cette erreur:
collect (Java.util.stream.Collector) dans Steam ne peut pas être appliqué à: (Java.util.stream.Collector, capture, Java.util.List>)
J'ai essayé de caster le paramètre mais cela me donne A
et R
non définis, et le IDE ne donne plus de suggestions.
Je suis curieux de savoir comment utiliser collect call
dans ce scénario, et je n'ai trouvé aucune information pouvant me guider correctement. Quelqu'un peut-il faire la lumière?
Le problème est que _Collectors.toList
_ , sans surprise, renvoie un _List<T>
_. Pas un ArrayList
.
_List<Long> ids = remove.stream()
.map(MyObj::getId)
.collect(Collectors.toList());
_
Programmez vers interface
.
De la documentation:
Renvoie un
Collector
qui accumule les éléments d'entrée dans un nouveauList
. Il n'y a aucune garantie sur le type, la mutabilité, la sérialisation ou la sécurité des threads duList
retourné ; si plus de contrôle sur la liste retournée est requis, utiliseztoCollection(Supplier)
.
Je souligne - vous ne pouvez même pas supposer que le List
retourné est modifiable, et encore moins qu'il appartient à une classe spécifique. Si vous voulez un ArrayList
:
_ArrayList<Long> ids = remove.stream()
.map(MyObj::getId)
.collect(Collectors.toCollection(ArrayList::new));
_
Notez également qu'il est habituel d'utiliser _import static
_ avec l'API Java 8 Stream
en ajoutant ainsi:
_import static Java.util.stream.Collectors.toCollection;
_
(Je déteste les étoiles _import static
_, cela ne fait que polluer l'espace de noms et ajouter de la confusion. Mais sélective _import static
_, en particulier avec les Java 8 classes utilitaires, peut réduire considérablement le code redondant)
Se traduirait par:
_ArrayList<Long> ids = remove.stream()
.map(MyObj::getId)
.collect(toCollection(ArrayList::new));
_
J'utilise beaucoup de blocs collecteurs où je crée un tableau vide et le remplis à l'aide d'une boucle, j'ai donc décidé que j'avais besoin d'une classe utilitaire pour ne pas écrire à nouveau les mêmes lignes et voici:
public class Collections {
public static <T, O> List<T> collect(Set<O> items, Function<? super O, ? extends T> mapper) {
return items.stream().map(mapper).collect(Collectors.toCollection(ArrayList::new));
}
}
et l'utiliser comme ça
List<Product> prods = Collections.collect(basket.getOrderItems(), OrderItem::getProduct);
ou comme ça
List<Long> prods = Collections.collect(basket.getOrderItems(), (item)->item.getProduct().getId());
Bien que cela puisse sembler beaucoup plus facile à lire, il semble que les flux soient un peu plus lents dans ce genre de scénarios, regardez ici