Java 8 stream api est une fonctionnalité très agréable et je l’aime vraiment. Une chose qui m'énerve est que 90% du temps, je veux avoir une entrée en tant que collection et une sortie en tant que collection. La conséquence est que je dois appeler les méthodes stream()
et collect()
tout le temps:
collection.stream().filter(p->p.isCorrect()).collect(Collectors.toList());
Existe-t-il une API Java qui me permettrait de sauter le flux et d’opérer directement sur les collections (comme linq
en c #?):
collection.filter(p->p.isCorrect)
Si vous voulez opérer sur des collections FluentIterable de Guava , il faut y aller!
Exemple (identifiez les 10 premiers clients vip):
FluentIterable
.from(customers)
.filter(customer -> customer.isVIP())
.transform(Client::getId)
.limit(10);
Oui, en utilisant Collection#removeIf(Predicate)
:
Supprime tous les éléments de cette collection qui satisfont le prédicat donné.
Notez que cela va changer la collection donnée, pas en retourner une nouvelle. Mais vous pouvez créer une copie de la collection et la modifier. Notez également que le prédicat doit être annulé pour agir en tant que filtre:
public static <E> Collection<E> getFilteredCollection(Collection<E> unfiltered,
Predicate<? super E> filter) {
List<E> copyList = new ArrayList<>(unfiltered);
// removeIf takes the negation of filter
copyList.removeIf(e -> { return !filter.test(e);});
return copyList;
}
Mais comme @Holger le suggère dans les commentaires, si vous choisissez de définir cette méthode d'utilitaire dans votre code et de l'utiliser partout où vous souhaitez obtenir une collection filtrée, vous ne faites que déléguer l'appel à la méthode collect
dans cet utilitaire. Votre code d'appelant sera alors plus concis.
public static <E> Collection<E> getFilteredCollection(Collection<E> unfiltered,
Predicate<? super E> filter) {
return unfiltered.stream()
.filter(filter)
.collect(Collectors.toList());
}
Vous pourriez aimer utiliser StreamEx
StreamEx.of(collection).filter(PClass::isCorrect).toList();
Cela a l’avantage d’être un peu plus bref tout en gardant l’immutabilité.
Les flux avaient une architecture bien définie, que vous pouvez lire beaucoup de choses sur . Vous voudrez peut-être lire à ce sujet avant de commencer dans cette voie.
Mais pourquoi ne pas implémenter une collection, qui implémente une interface de flux similaire qui enveloppe ce code pour vous?
public class StreamableCollection implements Collection, Stream {
...
}
Ensuite, vous pourriez faire des hypothèses difficiles pour votre cas d'utilisation. Vous pouvez toujours ouvrir un flux à partir de l'interface des collections, mais vous pouvez également accéder directement à l'intérieur de cette page, puis gérer son ouverture, je suppose.
streamableCollection cs = new streamableCollection();
cs.filter();
cs.stream();
Votre IDE vous demandera de tout implémenter ... il vous suffit de tout renvoyer aux implémentations par défaut.
Si vous avez besoin d'une vue filtrée sans modifier la collection d'origine, considérez le Collections2.filter()
de Guava.
Je pense aussi que l'API Stream est bonne, mais verbeuse pour les opérations courtes. J'ai utilisé ces méthodes utilitaires dans quelques projets:
import Java.util.List;
import Java.util.function.Function;
import Java.util.function.Predicate;
import Java.util.stream.Collectors;
import Java.util.stream.Stream;
public class Functions {
public static <T,V> List<V> map(final List<T> in, final Function<T, V> function) {
return in == null ? null : map(in.stream(), function);
}
public static <T,V> List<V> map(final Stream<T> in, final Function<T, V> function) {
return in == null ? null : in
.map(function)
.collect(Collectors.toList());
}
public static <T> List<T> filter(final List<T> in, final Predicate<T> predicate) {
return in == null ? null : filter(in.stream(), predicate);
}
public static <T> List<T> filter(final Stream<T> in, final Predicate<T> predicate) {
return in == null ? null : in
.filter(predicate)
.collect(Collectors.toList());
}
}
Cela me permet de faire par exemple.
List<String> wrapped = Functions.map(myList, each -> "[" + each + "]");
Normalement, j'importe également la méthode en statique.
Si vous êtes prêt à utiliser une bibliothèque tierce, vous pouvez utiliser Eclipse Collections , qui possède des API riches directement disponibles sous collections. Votre exemple peut être écrit comme ci-dessous avec Eclipse Collections.
collection.select(p->p.isCorrect)
collection.select(MyClass::isCorrect)
Remarque: je suis un partisan des collections Eclipse.
Oui, plusieurs bibliothèques traitent de la verbosité des flux de Java 8. Une liste incomplète:
Ma préférence va avec jOOL. Je l'utilise dans mes derniers projets. Les autres que je connais mais que je n’ai pas vraiment utilisés, je ne peux donc pas vous donner d’impression.
Votre exemple avec jOOL serait:
Seq.seq(collection).filter(p->p.isCorrect()).toList();
Vous pouvez essayer ceci depuis la bibliothèque de goyave. Cela semble un peu moins encombré que l'approche Stream.
ImmutableList.copyOf(Iterables.filter(collection, MyClass::isCorrect));
Voir Collections Google (bibliothèques Guava): ImmutableSet/List/Map and Filtering pour une discussion sur la technique.
Avec cyclops-react vous avez plusieurs options.
Nous pouvons utiliser les collections étendues paresseux
CollectionX<String> collection = ListX.of("hello","world");
CollectionX<String> filtered = collection.filter(p->p.isCorrect());
Il existe un support pour les collections étendues mutables, immuables et persistantes. Les opérations fonctionnelles sur les collections sont paresseuses (c'est-à-dire se comportent comme des flux pouvant être rejoués) et ne sont matérialisées qu'au premier accès.
Nous pouvons utiliser un puissant type de flux étendu
ReactiveSeq.fromIterable(collection)
.filter(p->p.isCorrect())
.toList();
[Divulgation Je suis le développeur principal de cyclops-react]