În Java 8, cum să obțineți Stream din Stream>? (Programare, Java, Colecții, Java 8, Java Stream)

Christian Hujer a intrebat.

În Java 8, folosind pachetele java.util.function și java.util.stream precum și noile caracteristici ale limbajului lambda și referințe la metode, , care este cea mai bună modalitate de a transforma un Stream<Collection<T>> într-un Stream<T>?

Iată exemplul cu soluția pe care am găsit-o până acum dar de care sunt nemulțumit. Pentru a crea un Stream<T> din a Stream<Collection<T>>, , folosesc collect().stream() cu un intermediar HashSet (a mea Collection este un Set).

import java.security.Provider;
import java.util.HashSet;
import static java.lang.System.out;
import static java.security.Security.getProviders;
import static java.security.Provider.Service;
import static java.util.Arrays.stream;

public class ListMessageDigests {
    public static void main(final String... args) {
        stream(getProviders())
            .map(Provider::getServices)
            .collect(HashSet<Service>::new, HashSet::addAll, HashSet::addAll)
            .stream()
            .filter(service -> "MessageDigest".equals(service.getType()))
            .map(Service::getAlgorithm)
            .sorted()
            .forEach(out::println);
    }   
}   

Există o modalitate mai elegantă de a converti un Stream<Collection<T>> în a Stream<T>? Cum ar fi a Stream<Set<Service>> din acest exemplu în a Stream<Service>? Nu sunt mulțumit de utilizarea unui intermediar HashSet și .collect().stream(), , mi se pare prea complicat.

P.S.:Știu că aș fi putut face asta pur și simplu:

import static java.security.Security.getAlgorithms;
public class ListMessageDigests {
    public static void main(final String... args) {
        getAlgorithms("MessageDigest")
            .forEach(out::println);
    }
}

Am folosit doar getProviders() și getServices pentru a construi rapid un Stream<Set<Service>> pentru a avea un Stream<Collection<T>> pentru a demonstra întrebarea.

Comentarii

  • În loc de algorithm -> out.format("%s%n", algorithm) puteți scrie out::println care este mai scurt și mai rapid. –  > Por Peter Lawrey.
  • @PeterLawrey Mulțumesc, ai dreptate. Am actualizat întrebarea și răspunsul în consecință. –  > Por Christian Hujer.
1 răspunsuri
Alex – GlassEditor.com

Puteți folosi flatMap cu Collection#stream

<T> Stream<T> flatten(Stream<? extends Collection<? extends T>> stream){
    return stream.flatMap(Collection::stream);
}

Codul final ar arăta astfel:

import static java.lang.System.out;
import static java.security.Provider.Service;
import static java.security.Security.getProviders;
import static java.util.Arrays.stream;

public class ListMessageDigests {
    public static void main(final String... args) {
        stream(getProviders())
            .flatMap(p -> p.getServices().stream())
            .distinct()
            .filter(service -> "MessageDigest".equals(service.getType()))
            .map(Service::getAlgorithm)
            .sorted()
            .forEach(out::println);
    }
}

Rețineți că fără a apela distinct s-ar putea să nu rezulte un flux cu exact aceleași elemente ca în exemplul tău, deoarece colectarea într-un set va elimina dublurile, dacă există.

Comentarii

  • ați putea înlocui .map(Provider::getServices) .flatMap(Set::stream) cu .flatMap(p -> p.getServices().stream()) –  > Por Peter Lawrey.
  • @PeterLawrey Mulțumesc, aveți dreptate. Mi-am actualizat întrebarea și răspunsul în consecință. –  > Por Christian Hujer.
  • @Alex Vă mulțumim pentru că ați subliniat distinct. Am actualizat răspunsul în consecință. –  > Por Christian Hujer.