image

Acesse bootcamps ilimitados e +650 cursos

50
%OFF
CLAUDIONEI AGUIAR
CLAUDIONEI AGUIAR13/09/2024 11:01
Compartilhe

Java Streams na Prática: Exemplos e Boas Práticas

  • #Java

Este artigo foi adaptado de uma obra originalmente publicada no Medium, escrita por Hùng Trần no Javarevisited, com o título: "Melhores práticas para usar Java Stream", disponível em: https://medium.com/javarevisited/best-practices-for-using-java-stream-f0f7585f13ba. que discute as melhores práticas ao trabalhar com Java Streams. A seguir, abordaremos essas práticas, traduzidas e reorganizadas, para ajudar os desenvolvedores a escreverem códigos mais eficientes e fáceis de manter utilizando Java Streams.

Java Streams são uma ferramenta poderosa que permite manipular coleções de dados de maneira eficiente e elegante. Para acompanhar os exemplos apresentados aqui, recomendamos o uso de uma IDE como IntelliJ IDEA ou Eclipse. Caso prefira, você também pode utilizar um editor de código online como o Repl.it ou JDoodle, onde você pode clicar no botão de "Executar" para testar os exemplos e visualizar os resultados diretamente.

Principais Operações com Java Streams

Abaixo estão algumas das operações mais comuns com Java Streams. Você pode copiar e colar o código no Repl.it ou JDoodle, clicar em Run (Executar), e ver o resultado imediatamente após a execução.

1. filter(): Remove elementos que não atendem a uma condição específica.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
 
public class ExemploFiltro {
 public static void main(String[] args) {
     List<String> nomes = Arrays.asList("João", "Paulo", "Carlos", "Rita");
     List<String> nomesFiltrados = nomes.stream()
             .filter(nome -> nome.startsWith("J"))
             .collect(Collectors.toList());
     System.out.println(nomesFiltrados);
 }
}

Resultado:

[João]

2. map(): Converte cada elemento do fluxo para outro tipo.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
 
public class ExemploMap {
 public static void main(String[] args) {
     List<String> palavras = Arrays.asList("cafe", "codigo", "java");
     List<String> palavrasMaiusculas = palavras.stream()
             .map(String::toUpperCase)
             .collect(Collectors.toList());
     System.out.println(palavrasMaiusculas);
 }
}

Resultado:

[CAFE, CODIGO, JAVA]

3. flatMap(): Combina múltiplos fluxos em um único fluxo.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
 
public class ExemploFlatMap {
 public static void main(String[] args) {
     List<List<Integer>> numerosAninhados = Arrays.asList(
             Arrays.asList(1, 2),
             Arrays.asList(3, 4),
             Arrays.asList(5, 6)
     );
     List<Integer> numerosSimples = numerosAninhados.stream()
             .flatMap(List::stream)
             .collect(Collectors.toList());
     System.out.println(numerosSimples);
 }
}

Resultado:

[1, 2, 3, 4, 5, 6]

4. distinct(): Remove elementos duplicados do fluxo.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
 
public class ExemploDistinct {
 public static void main(String[] args) {
     List<Integer> numeros = Arrays.asList(1, 2, 2, 3, 3, 4, 5, 5);
     List<Integer> numerosDistintos = numeros.stream()
             .distinct()
             .collect(Collectors.toList());
     System.out.println(numerosDistintos);
 }
}

Resultado:

[1, 2, 3, 4, 5]

5. sorted(): Ordena os elementos do fluxo.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
 
public class ExemploOrdenacao {
 public static void main(String[] args) {
     List<Integer> numeros = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6);
     List<Integer> numerosOrdenados = numeros.stream()
             .sorted()
             .collect(Collectors.toList());
     System.out.println(numerosOrdenados);
 }
}

Resultado:

[1, 1, 2, 3, 4, 5, 6, 9]

6. peek(): Útil para depurar ou inspecionar o fluxo.

import java.util.stream.IntStream;
 
public class ExemploPeek {
 public static void main(String[] args) {
     IntStream.range(1, 6)
             .peek(n -> System.out.println("Processando: " + n))
             .map(n -> n * n)
             .forEach(System.out::println);
 }
}

Resultado:

Processando: 1
1
Processando: 2
4
Processando: 3
9
Processando: 4
16
Processando: 5
25

7. limit() e skip(): Controlam quantos elementos são processados.

import java.util.stream.IntStream;
 
public class ExemploLimitSkip {
 public static void main(String[] args) {
     System.out.println("Limit:");
     IntStream.range(1, 100)
             .limit(5)
             .forEach(System.out::println);
 
     System.out.println("Skip:");
     IntStream.range(1, 11)
             .skip(5)
             .forEach(System.out::println);
 }
}

Resultado:

Limit:
1
2
3
4
5
Skip:
6
7
8
9
10

8. reduce(): Executa operações de agregação.

import java.util.Arrays;
 
public class ExemploReduce {
 public static void main(String[] args) {
     Integer[] numeros = {1, 2, 3, 4, 5};
     int soma = Arrays.stream(numeros)
             .reduce(0, Integer::sum);
     System.out.println("Soma: " + soma);
 }
}

Resultado:

Soma: 15

9. collect(): Converte o fluxo em uma coleção.

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
 
public class ExemploCollect {
 public static void main(String[] args) {
     List<Integer> numerosColetados = Stream.of(1, 2, 3, 4, 5)
             .collect(Collectors.toList());
     System.out.println(numerosColetados);
 }
}

Resultado:

[1, 2, 3, 4, 5]

Dicas e Práticas Recomendadas

  1. Escreva Código Legível
  2. Coloque cada operação de stream em uma nova linha para facilitar a leitura e depuração do código.
  3. Cheque para null em Operações de Mapeamento
  4. Sempre verifique se o valor não é null quando usar map() ou filter().
  5. Cuidado com o Uso Excessivo de Paralelismo
  6. Embora parallelStream() possa aumentar o desempenho, nem sempre é vantajoso. Utilize-o somente quando for realmente necessário.
  7. Nomeie Variáveis de Forma Clara
  8. Utilize nomes de variáveis descritivos. Evite nomes como a, b e c, que dificultam a compreensão do código.
  9. Atenção ao Converter Listas em Mapas
  10. Ao usar collect() para converter listas em mapas, verifique a existência de chaves duplicadas para evitar exceções.
  11. Uso de Optional
  12. Optional é útil em casos como findFirst() ou findAny(), ajudando a lidar com possíveis valores ausentes.
  13. Evite o Overuse de Streams
  14. Embora streams facilitem a escrita de código conciso, seu uso excessivo pode tornar o código difícil de manter. Use streams de forma equilibrada.

Java Streams são uma ferramenta valiosa para simplificar a manipulação de coleções de dados. Ao seguir essas práticas recomendadas e usar os exemplos apresentados, você poderá escrever código mais eficiente e de fácil manutenção. Lembre-se de equilibrar o uso de streams com o código imperativo tradicional para evitar complexidades desnecessárias.

Compartilhe
Comentários (0)