2014-12-25 7 views
4

В Java 8, используя пакеты java.util.function и java.util.stream, а также новые функции языка лямбда и метод ссылается, что это лучший способ превратить Stream<Collection<T>> в Stream<T>?В Java 8, как получить Stream <T> от Stream <? extends Collection <T>>?

Вот пример с решением, которое я нашел до сих пор, но я недоволен. Чтобы создать Stream<T> от Stream<Collection<T>>, я использую collect().stream() с промежуточным звеном HashSet (мой Collection - 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); 
    } 
} 

Есть ли более элегантный способ для преобразования Stream<Collection<T>> в Stream<T>? Как Stream<Set<Service>> в этом примере в Stream<Service>? Я не доволен использованием промежуточного HashSet и .collect().stream(), он чувствует себя сложным для меня.

P.S .: Я знаю, что я мог бы просто сделать это:

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

Я использовал только getProviders() и getServices быстро построить Stream<Set<Service>> иметь Stream<Collection<T>> продемонстрировать вопрос.

+1

Вместо 'algorithm -> out.format («% s% n », алгоритм)' вы можете написать 'out :: println', который короче и быстрее. –

+0

@PeterLawrey Спасибо, ты прав. Я обновил свой вопрос и ответ соответственно. –

ответ

9

Вы можете использовать flatMap с Collection#stream

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

окончательный код будет выглядеть следующим образом:

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

Обратите внимание, что без вызова distinct это не может привести к потоку с точно такими же элементами как ваш пример, поскольку сбор в набор удалит дубликаты, если они есть.

+2

вы можете заменить '.map (Provider :: getServices) .flatMap (Set :: stream)' с '.flatMap (p -> p.getServices(). Stream())' –

+0

@PeterLawrey Спасибо, ты правильно. Я обновил свой вопрос и ответ соответственно. –

+0

@Alex Спасибо за указание 'отчетливый'. Я соответствующим образом обновил ответ. –

Смежные вопросы