DEV Community

FUNDAMENTOS JAVA
FUNDAMENTOS JAVA

Posted on

7.4 e 7.5 Collectors

Podemos usar o método collect para resgatar esses elementos do nosso
Stream para uma List. Porém, repare sua assinatura

 <R> R collect(Supplier<R> supplier,
 BiConsumer<R, ? super T> accumulator,
 BiConsumer<R, R> combiner);
Enter fullscreen mode Exit fullscreen mode

Ela recebe três argumentos. Os três são interfaces funcionais. O primeiro é uma factory que vai criar o objeto que será devolvido no final da coleta. O segundo é o método que será invocado para adicionar cada elemento. O terceiro pode ser invocados e precisarmos adicionar mais de um elemento ao mesmo tempo (por exemplo, se formos usar uma estratégia de coletar elementos paralelamente, como veremos no futuro).
Para fazer essa transformação simples, eu teria que escrever um código como esse:

 Supplier<ArrayList<Usuario>> supplier = ArrayList::new;
 BiConsumer<ArrayList<Usuario>, Usuario> accumulator =
 ArrayList::add;
 BiConsumer<ArrayList<Usuario>, ArrayList<Usuario>> combiner =
 ArrayList::addAll;
 List<Usuario> maisQue100 = usuarios.stream()
 .filter(u-> u.getPontos() > 100)
 .collect(supplier, accumulator, combiner);

Enter fullscreen mode Exit fullscreen mode

Bastante complicado, não acha? Poderíamos tentar simplificar deixando o código em um único statement, mas ainda sim teríamos uma operação complicada e perderíamos um pouco na legibilidade:

 usuarios.stream()
 .filter(u-> u.getPontos() > 100)
 .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
Enter fullscreen mode Exit fullscreen mode

A API simplificou esse trabalho, claro. Temos uma outra opção de uso do método collect, que recebe um Collector como parâmetro:

 <R, A> R collect(Collector<? super T, A, R> collector);
Enter fullscreen mode Exit fullscreen mode

A interface Collector nada mais é que alguém que tem um supplier, um accumulator e um combiner. A vantagem é que existem vários Collectors prontos.
Podemos simplificar bastante nosso código, passando como parâmetro em nosso método collect o Collectors.toList(), uma das implementações dessa nova interface.

 usuarios.stream()
 .filter(u-> u.getPontos() > 100)
 .collect(Collectors.toList());
Enter fullscreen mode Exit fullscreen mode

Collectors.toList devolve um coletor bem parecido com o qual criamos na mão, com a diferença de que ele devolve uma lista que não sabemos se é mutável, sé thread-safe ou qual a sua implementação. Fazendo um import estático podemos deixar o código um pouco mais enxuto, em um único statement.

usuarios.stream()
 .filter(u-> u.getPontos() > 100)
 .collect(toList());
Enter fullscreen mode Exit fullscreen mode

Pronto! Agora conseguimos coletar o resultado das transformações no nosso
Stream emum List:

 List<Usuario> maisQue100 = usuarios.stream()
 .filter(u-> u.getPontos() > 100)
 .collect(toList());
Enter fullscreen mode Exit fullscreen mode

Apesar do import estático deixar nosso código mais enxuto, evitaremos abusar. O motivo é simples: para ficar mais claro durante a leitura do livro qual método estamos invocando.

7.5 Avançado: porque não há um toList em Stream?

Ausência de toList como método default

  • Brian Goetz e outros líderes da comunidade Java decidiram não incluir toList diretamente na API do Java 8.
  • O motivo é evitar um crescimento excessivo da API com métodos que poderiam ser úteis, mas não essenciais.

Alternativas para coletar dados de um Stream

  • toSet(): Coleta os elementos em um Set.
Set<Usuario> maisQue100 = usuarios
  .stream()
  .filter(u -> u.getPontos() > 100)
  .collect(Collectors.toSet());

Enter fullscreen mode Exit fullscreen mode
  • toCollection(Supplier): Permite definir a implementação da coleção retornada.
Set<Usuario> set = stream.collect(
  Collectors.toCollection(HashSet::new)
);

Enter fullscreen mode Exit fullscreen mode

O Supplier funciona como uma fábrica, fornecendo a estrutura desejada para os dados coletados.

  • Uso de toArray() Converte um Stream em um array de Object[] ou de um tipo específico.
Usuario[] array = stream.toArray(Usuario[]::new);

Enter fullscreen mode Exit fullscreen mode

Pode receber um IntSupplier para definir o tamanho do array.

Top comments (0)