API peek () do Java 8 Streams

API peek () do Java 8 Streams

1. Introdução

OJava Stream API nos apresenta uma alternativa poderosa para o processamento de dados.

Neste breve tutorial, vamos nos concentrar empeek(), um método frequentemente mal compreendido.

2. Exemplo rápido

Vamos sujar as mãos e tentar usarpeek(). Temos um fluxo de nomes e queremos imprimi-los no console.

Comopeek() espera umConsumer<T> como seu único argumento, parece um bom ajuste, então vamos tentar:

Stream nameStream = Stream.of("Alice", "Bob", "Chuck");
nameStream.peek(System.out::println);

No entanto, o trecho acima não produz saída. Para entender o porquê, vamos fazer uma rápida atualização sobre os aspectos do ciclo de vida do stream.

3. Intermediário vs. Operações de Terminal

Lembre-se de que os fluxos têm três partes: uma fonte de dados, zero ou mais operações intermediárias e zero ou uma operação de terminal.

A fonte fornece os elementos para o pipeline.

Operações intermediárias obtêm elementos um por um e os processam. All intermediate operations are lazy, and, as a result, no operations will have any effect until the pipeline starts to work.

Operações de terminal significam o fim do ciclo de vida do fluxo. Mais importante para o nosso cenário, elesinitiate the work in the pipeline.

4. peek() Uso

O motivo pelo qualpeek() não funcionou em nosso primeiro exemplo é queit’s an intermediate operation and we didn’t apply a terminal operation para o pipeline. Alternativamente, poderíamos ter usadoforEach() com o mesmo argumento para obter o comportamento desejado:

Stream nameStream = Stream.of("Alice", "Bob", "Chuck");
nameStream.forEach(System.out::println);

peek()'sJavadoc page diz: “This method exists mainly to support debugging, where you want to see the elements as they flow past a certain point in a pipeline“.

Vamos considerar este snippet da mesma página Javadoc:

Stream.of("one", "two", "three", "four")
  .filter(e -> e.length() > 3)
  .peek(e -> System.out.println("Filtered value: " + e))
  .map(String::toUpperCase)
  .peek(e -> System.out.println("Mapped value: " + e))
  .collect(Collectors.toList());

Demonstra como observamos os elementos que passaram em cada operação.

Além disso,peek() pode ser útil em outro cenário: quandowe want to alter the inner state of an element. Por exemplo, digamos que queremos converter todos os nomes de usuários em letras minúsculas antes de imprimi-los:

Stream userStream = Stream.of(new User("Alice"), new User("Bob"), new User("Chuck"));
userStream.peek(u -> u.setName(u.getName().toLowerCase()))
  .forEach(System.out::println);

Alternativamente, poderíamos ter usadomap(), maspeek() é mais conveniente, pois não queremos substituir o elemento.

5. Conclusão

Neste breve tutorial, vimos um resumo do ciclo de vida do stream para entender comopeek() funciona. Também vimos dois casos de uso diário em que usarpeek() é a opção mais direta.

E como de costume, os exemplos estão disponíveisover on GitHub.