web-dev-qa-db-fra.com

Itérer une énumération dans 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 en son sein.

70
Tapas Bose

Si vous n'aimez pas le fait que Collections.list(Enumeration) copie l'intégralité du contenu dans une liste (temporaire) avant le début de l'itération, vous pouvez vous aider avec une méthode d'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 fonction import static)…

33
Holger

(Cette réponse montre l'une des nombreuses options. Juste parce que a avait marque d'acceptation, ne signifie pas 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. OMI:
- for Java 8 réponse de Holger est le plus gentil, car en plus d'être simple, il ne nécessite pas d'itération supplémentaire, ce qui se produit dans la solution minière.
- pour Java 9 Je choisirais une solution de réponse Tagir Valeev )


Vous pouvez copier des éléments de votre Enumeration vers ArrayList avec Collections.list et ensuite l'utiliser comme

Collections.list(yourEnumeration).forEach(yourAction);
84
Pshemo

S'il y a beaucoup de Enumerations dans votre code, je vous recommande de créer une méthode d'assistance statique, qui convertit un Enumeration en Stream. La méthode statique pourrait 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 importation 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(...));
50
nosid

Depuis Java-9, il y aura une nouvelle méthode par défaut Enumeration.asIterator() qui simplifiera la solution pure Java:

nets.asIterator().forEachRemaining(iface -> { ... });
45
Tagir Valeev

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 telles que NONNULL ou DISTINCT.

Après avoir appliqué les importations statiques, cela deviendra plus lisible:

stream(spliteratorUnknownSize(toIterator(enumeration), IMMUTABLE), false)

vous avez maintenant un standard Java 8 à utiliser de quelque manière que ce soit! Vous pouvez passer true pour le traitement en parallèle.

Pour convertir d'énumération en itérateur, utilisez l'un des éléments suivants:

  • CollectionUtils.toIterator() à partir du printemps 3.2 ou vous pouvez utiliser
  • IteratorUtils.asIterator() de Apache Commons Collections 3.2
  • Iterators.forEnumeration() de Google Guava
11
Arne Burmeister

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

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

6
Marek Gregor

Je sais que la question est ancienne, mais je voulais présenter une alternative aux fonctionnalités de Collections.asList et Stream. Comme la question s'intitule "Itérer une énumération", je reconnais parfois que vous souhaitiez utiliser une expression lambda, mais une boucle for améliorée peut être préférable, car l'objet énuméré peut générer une exception et la boucle for est plus facile à encapsuler dans une tentative plus grande. segment de code de capture (les lambdas exigent que les exceptions déclarées soient capturées dans le lambda). À cette fin, on utilise ici un lambda pour créer un Iterable utilisable dans une boucle for et ne préchargeant 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();
        }
    };
}
4
user579013