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.