web-dev-qa-db-fra.com

Comment utiliser l'appel à frais virés dans Java 8?

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?

22
Alexandru Severin

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 nouveau List. Il n'y a aucune garantie sur le type, la mutabilité, la sérialisation ou la sécurité des threads du List retourné ; si plus de contrôle sur la liste retournée est requis, utilisez toCollection(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));
_
47
Boris the Spider

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

2
azerafati