简体   繁体   中英

In Java 8, how to get Stream<T> from Stream<? extends Collection<T>>?

In Java 8, using the packages java.util.function and java.util.stream as well as the new language features lambda and method references , what is the best way to turn a Stream<Collection<T>> into a Stream<T> ?

Here's the example with the solution that I've found so far but am unhappy with. In order to create a Stream<T> from a Stream<Collection<T>> , I use collect().stream() with an intermediate HashSet (my Collection is a 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);
    }   
}   

Is there a more elegant way to convert a Stream<Collection<T>> to a Stream<T> ? Like a Stream<Set<Service>> in this example into a Stream<Service> ? I am not happy with using an intermediate HashSet and .collect().stream() , it feels to complicated to me.

PS: I know that I could've simply done this:

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

I was only using getProviders() and getServices to quickly construct a Stream<Set<Service>> to have a Stream<Collection<T>> to demonstrate the question.

You can use flatMap with Collection#stream

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

The final code would then look like this:

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);
    }
}

Note that without calling distinct this might not result in a stream with exactly the same elements as your example, since collecting into a set will remove duplicates if there are any.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM