Goyave: Pourquoi n’y a-t-il pas de fonction Lists.filter ()?

Y at-il une raison pour laquelle il y a

Lists.transform() 

mais non

 Lists.filter() 

?

Comment filtrer une liste correctement? je pourrais utiliser

 new ArrayList(Collection2.filter()) 

Bien sûr, mais cela ne garantit pas que ma commande rest la même, si je comprends bien.

Il n’a pas été implémenté car il exposerait un grand nombre de méthodes lentes, telles que #get (index) sur la vue List retournée (invitant les bogues de performance). Et ListIterator serait aussi pénible à implémenter (bien que j’ai soumis un patch il y a des années pour couvrir cela).

Étant donné que les méthodes indexées ne peuvent pas être efficaces dans la vue Liste filtrée, il est préférable de choisir une itération filtrée, qui ne les contient pas.

Vous pouvez utiliser Iterables.filter , qui maintiendra définitivement l’ordre.

Notez qu’en construisant une nouvelle liste, vous copiez les éléments (juste des références, bien sûr) – ce ne sera donc pas une vue en direct sur la liste d’origine. Créer une vue serait assez compliqué – considérez cette situation:

 Predicate predicate = /* predicate returning whether the builder is empty */ List builders = Lists.newArrayList(); List view = Lists.filter(builders, predicate); for (int i = 0; i < 10000; i++) { builders.add(new StringBuilder()); } builders.get(8000).append("bar"); StringBuilder firstNonEmpty = view.get(0); 

Cela devrait parcourir toute la liste originale, en appliquant le filtre à tout. Je suppose que cela pourrait exiger que la correspondance des prédicats ne change pas au cours de la vie de la vue, mais cela ne serait pas entièrement satisfaisant.

(Il suffit de deviner, peut-être que l'un des responsables de la goyave va comprendre la vraie raison 🙂

Je pourrais bien sûr utiliser new List(Collection2.filter()) , mais cela ne garantit pas que ma commande rest la même.

Ce n’est pas vrai Collections2.filter() est une fonction évaluée paresseusement – elle ne filtre pas réellement votre collection tant que vous n’accédez pas à la version filtrée. Par exemple, si vous effectuez une itération sur la version filtrée, les éléments filtrés apparaîtront hors de l’iterator dans le même ordre que votre collection d’origine (moins les éléments filtrés, évidemment).

Peut-être pensiez-vous faire le filtrage avant, puis déverser les résultats dans une Collection arbitraire et non ordonnée de quelque forme que ce soit.

Donc, si vous utilisez la sortie de Collections2.filter() comme entrée dans une nouvelle liste, votre commande d’origine sera conservée.

En utilisant les importations statiques (et la fonction Lists.newArrayList ), cela devient assez succinct:

 List filteredList = newArrayList(filter(originalList, predicate)); 

Notez que si Collections2.filter ne parcourra pas avec impatience la collection sous-jacente, Lists.newArrayList fera : il extraira tous les éléments de la collection filtrée et les copiera dans une nouvelle ArrayList .

Comme mentionné par Jon, vous pouvez utiliser Iterables.filter(..) ou Collections2.filter(..) et si vous n’avez pas besoin d’une vue en direct, vous pouvez utiliser ImmutableList.copyOf(Iterables.filter(..)) ou Lists.newArrayList( Iterables.filter(..)) et oui l’ordre sera maintenu.

Si vous êtes vraiment intéressé par la question de savoir pourquoi , vous pouvez visiter https://github.com/google/guava/issues/505 pour plus de détails.

En résumant ce que les autres ont dit, vous pouvez facilement créer un wrapper générique pour filtrer les listes:

 public static  List filter(Iterable userLists, Predicate predicate) { return Lists.newArrayList(Iterables.filter(userLists, predicate)); }