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.

66
demandé sur Tapas Bose 2014-04-24 10:51:58

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)...

31
répondu Holger 2015-10-20 17:16:10

(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);
81
répondu Pshemo 2018-02-14 21:44:21

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(...));
47
répondu nosid 2014-04-24 18:01:46

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 -> { ... });
44
répondu Tagir Valeev 2015-09-17 10:21:43

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
9
répondu Arne Burmeister 2015-09-17 10:06:01

Pour Java 8, la transformation la plus simple de l'énumération en flux est:

Collections.list(NetworkInterface.getNetworkInterfaces()).stream()

3
répondu Marek Gregor 2018-01-29 14:45:16

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();
        }
    };
}
0
répondu user579013 2018-04-19 14:52:13