DEV Community

Java Efetivo (livro)
Java Efetivo (livro)

Posted on • Updated on

Item 45: Seja criterioso ao utilizar as streams

  • Resumo

API de Streams no Java 8:
Facilita operações em massa, sequenciais ou paralelas.

Duas principais abstrações: stream (sequência de elementos) e stream pipeline (cálculo de várias etapas).

Origem dos Elementos:

  • Coleções, arrays, arquivos, regex, geradores de números aleatórios, outras streams.
  • Suporte para referências de objetos e tipos primitivos (int, long, double).

Componentes de uma Stream Pipeline:
Stream de origem: ponto inicial.

Operações intermediárias: transformam a stream (ex.: map, filter).

Operação terminal: finaliza o processamento (ex.: collect, forEach).

Avaliação Preguiçosa:
A avaliação começa apenas na operação terminal.
Permite trabalhar com streams infinitas.
Pipelines sem operação terminal não fazem nada.

Fluência e Encadeamento:
API fluente permite encadear chamadas em uma única expressão.

Execução Paralela:
Pode ser ativada com parallel(), mas é raramente recomendada.

Cuidado no Uso de Streams:
Podem tornar o código curto e limpo, mas também ilegível e difícil de manter se usadas indevidamente.

Exemplo de Uso:
Comparação entre soluções com streams e iteração para encontrar anagramas.
Uso de computeIfAbsent para simplificar maps com múltiplos valores por chave.

Nomeação Criteriosa:
Nomes de parâmetros lambda são importantes para a legibilidade.

Quando Usar Streams:
Para tarefas como transformação, filtragem, combinação, acumulação e busca de elementos.

Limitações das Streams:
Difícil acessar elementos correspondentes de múltiplos estágios.
Complicado processar valores primitivos como char.

Escolha entre Streams e Iteração:
Não há regra fixa; escolha com base na clareza, manutenção e preferência de equipe.
Algumas tarefas são mais adequadas para streams, outras para iteração, e outras ainda para uma combinação de ambas.

Conclusão:

Use streams quando forem a melhor ferramenta para o trabalho, mas seja criterioso para evitar complicar o código.

Se você não tem certeza se uma tarefa é melhor atendida por
uma stream ou por uma iteração, tente usar as duas e veja qual delas
funciona melhor

Exemplos do Livro
Anagramas em Streams:
O programa lê palavras de um arquivo e organiza anagramas, palavras com as mesmas letras em ordem diferente.
Usa computeIfAbsent para mapear palavras para uma lista de anagramas.
Três versões do programa:
Versão 1 (iterativa): Usa loops para construir um map de anagramas.
Versão 2 (streams intensivo): Usa uma pipeline de streams para realizar o mesmo trabalho.
Versão 3 (híbrido): Combina streams e loops, resultando em um código mais claro e conciso.

Image description

Image description

Image description

Ver exemplo: Anagramas.java

Manuseio de Caracteres com Streams:

Demonstração de problemas ao usar streams para processar char.
Exemplo: “Hello world!”.chars() retorna uma stream de int, não char.
Necessidade de conversão para o tipo correto.

Image description

Primos de Mersenne:

Exibe os primeiros 20 primos de Mersenne.
Uso de Stream.iterate para gerar números primos.
Mostra como acessar valores anteriores na pipeline para exibir o expoente junto com o primo de Mersenne.

Image description

Image description

Ver exemplo StreamExamples.java

Inicialização de um Baralho de Cartas:

Dois métodos para inicializar um baralho:
Versão iterativa: Usa loops for-each aninhados.
Versão com streams: Usa flatMap para criar o produto cartesiano de Rank e Suit.
Discussão sobre qual abordagem é mais clara e preferível, dependendo da familiaridade da equipe com streams e programação funcional.

Image description

Image description

Esses exemplos mostram a versatilidade e as limitações das streams, além de enfatizar a importância de escolher a abordagem mais adequada para cada caso.

Ver exemplo DeckInicialization.java

Top comments (0)