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.
P.S.: 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With