Itérer une énumération en Java 8
Est-il possible d'itérer un Enumeration
en utilisant l'Expression Lambda? Quelle sera la représentation Lambda de l'extrait de code suivant:
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
while (nets.hasMoreElements()) {
NetworkInterface networkInterface = nets.nextElement();
}
Je n'ai trouvé aucun flux à l'intérieur.
7 réponses
Si vous n'aimez pas le fait que Collections.list(Enumeration)
copie tout le contenu dans une liste (temporaire) avant le début de l'itération, vous pouvez vous aider avec une méthode utilitaire simple:
public static <T> void forEachRemaining(Enumeration<T> e, Consumer<? super T> c) {
while(e.hasMoreElements()) c.accept(e.nextElement());
}
Ensuite, vous pouvez simplement faire forEachRemaining(enumeration, lambda-expression);
(attention à la fonctionnalité import static
)...
(Cette réponse montre l'une des nombreuses options. Ce n'est pas parce que A eu une marque d'acceptation que c'est le meilleur. Je suggère de lire d'autres réponses et d'en choisir une en fonction de la situation dans laquelle vous vous trouvez. Personnellement, pour Java 8, je trouve la réponse de Holger la plus agréable car elle est aussi simple mais n'a pas besoin d'itération supplémentaire - ce qui se produit dans la solution de la mienne. Mais pour Java 9 solution visite Tagir Valeev réponse)
Vous pouvez copier des éléments de votre Enumeration
pour ArrayList
avec Collections.list
et puis l'utiliser comme
Collections.list(yourEnumeration).forEach(yourAction);
S'il y a beaucoup d'énumérations dans votre code, je recommande de créer une méthode d'aide statique, qui convertit une énumération en un flux . La méthode statique peut ressembler à ceci:
public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) {
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(
new Iterator<T>() {
public T next() {
return e.nextElement();
}
public boolean hasNext() {
return e.hasMoreElements();
}
},
Spliterator.ORDERED), false);
}
Utilisez la méthode avec un import statique . Contrairement à la solution de Holger, vous pouvez bénéficier des différentes opérations stream , ce qui pourrait rendre le code existant encore plus simple. Voici un exemple:
Map<...> map = enumerationAsStream(enumeration)
.filter(Objects::nonNull)
.collect(groupingBy(...));
Depuis Java-9, Il y aura une nouvelle méthode par défautEnumeration.asIterator()
ce qui rendra la solution Java pure plus simple:
nets.asIterator().forEachRemaining(iface -> { ... });
Vous pouvez utiliser la combinaison suivante de fonctions standard:
StreamSupport.stream(Spliterators.spliteratorUnknownSize(CollectionUtils.toIterator(enumeration), Spliterator.IMMUTABLE), parallel)
Vous pouvez également ajouter d'autres caractéristiques, comme les NONNULL
ou DISTINCT
.
Après avoir appliqué des importations statiques, cela deviendra plus lisible:
stream(spliteratorUnknownSize(toIterator(enumeration), IMMUTABLE), false)
Maintenant, vous avez un flux Java 8 standard à utiliser de quelque manière que ce soit! Vous pouvez passer true
pour un traitement parallèle.
Pour convertir L'énumération en itérateur, utilisez l'une des options suivantes:
- {[5] } de printemps 3.2 ou vous pouvez utiliser
-
IteratorUtils.asIterator()
de Apache Collections Communes 3.2 -
Iterators.forEnumeration()
de Google Goyave
Pour Java 8, la transformation la plus simple de l'énumération en flux est:
Collections.list(NetworkInterface.getNetworkInterfaces()).stream()
Je sais que c'est une vieille question, mais je voulais présenter une alternative aux Collections.fonctionnalité asList et Stream. Puisque la question est intitulée "itérer une énumération" , je reconnais parfois que vous voulez utiliser une expression lambda mais une boucle for améliorée peut être préférable car l'objet énuméré peut lancer une exception et la boucle for Est plus facile à encapsuler dans un segment de code try-catch plus grand (les lambdas nécessitent des exceptions déclarées pour être interceptées dans le lambda). À cette fin, voici utiliser un lambda pour créer un itérable qui est utilisable dans une boucle for et ne précharge pas l'énumération:
/**
* Creates lazy Iterable for Enumeration
*
* @param <T> Class being iterated
* @param e Enumeration as base for Iterator
* @return Iterable wrapping Enumeration
*/
public static <T> Iterable<T> enumerationIterable(Enumeration<T> e)
{
return () -> new Iterator<T>()
{
@Override
public T next()
{
return e.nextElement();
}
@Override
public boolean hasNext()
{
return e.hasMoreElements();
}
};
}