Stream API no Java
Stream API no Java
A Stream API foi introduzida no Java 8 com o objetivo de simplificar o processamento de coleções de dados. Ela permite realizar operações como filtragem, transformação, ordenação e agregação de forma declarativa, reduzindo a necessidade de estruturas de repetição tradicionais, como o for.
Uma Stream não armazena dados. Ela representa um fluxo de elementos que pode ser processado por uma sequência de operações.
Conceito
Uma Stream é uma sequência de elementos que suporta operações para processamento de dados.
O processamento ocorre em três etapas principais:
- Fonte de dados (Source)
- Operações intermediárias (Intermediate Operations)
- Operação terminal (Terminal Operation)
Estrutura Geral
colecao.stream()
.operacaoIntermediaria()
.operacaoIntermediaria()
.operacaoTerminal();
Criação de Streams
A partir de uma Lista
List<String> nomes = List.of("Ana", "Carlos", "João");
Stream<String> stream = nomes.stream();
A partir de um Array
String[] nomes = {"Ana", "Carlos", "João"};
Stream<String> stream = Arrays.stream(nomes);
Utilizando Stream.of()
Stream<String> stream =
Stream.of("Ana", "Carlos", "João");
Operações Intermediárias
As operações intermediárias transformam ou filtram os dados e retornam uma nova Stream.
filter()
Utilizado para selecionar elementos que atendem a uma condição.
nomes.stream()
.filter(nome -> nome.startsWith("J"));
Resultado:
João
map()
Utilizado para transformar os elementos.
nomes.stream()
.map(String::toUpperCase);
Resultado:
ANA
CARLOS
JOÃO
sorted()
Ordena os elementos.
nomes.stream()
.sorted();
Resultado:
Ana
Carlos
João
distinct()
Remove elementos duplicados.
List<Integer> numeros =
List.of(1, 2, 2, 3, 3, 4);
numeros.stream()
.distinct();
Resultado:
1, 2, 3, 4
limit()
Limita a quantidade de elementos processados.
numeros.stream()
.limit(3);
Resultado:
1, 2, 3
Operações Terminais
As operações terminais encerram o fluxo e produzem um resultado.
forEach()
Executa uma ação para cada elemento.
nomes.stream()
.forEach(System.out::println);
collect()
Converte o resultado da Stream em uma coleção.
List<String> resultado =
nomes.stream()
.filter(nome -> nome.length() > 3)
.toList();
count()
Conta os elementos.
long total =
nomes.stream()
.count();
findFirst()
Retorna o primeiro elemento encontrado.
Optional<String> nome =
nomes.stream()
.findFirst();
reduce()
Combina todos os elementos em um único resultado.
int soma =
List.of(1,2,3,4,5)
.stream()
.reduce(0, Integer::sum);
Resultado:
15
Exemplo Completo
Objetivo: obter os nomes com mais de 4 caracteres em letras maiúsculas.
List<String> nomes =
List.of("Ana", "Carlos", "João", "Fernanda");
List<String> resultado =
nomes.stream()
.filter(nome -> nome.length() > 4)
.map(String::toUpperCase)
.toList();
System.out.println(resultado);
Saída:
[CARLOS, FERNANDA]
Lazy Evaluation
As operações intermediárias são executadas apenas quando uma operação terminal é chamada.
Exemplo:
nomes.stream()
.filter(nome -> {
System.out.println(nome);
return true;
});
Nenhuma saída será produzida porque não existe operação terminal.
Ao adicionar:
.count();
o processamento será executado.
Parallel Stream
Permite processar dados em paralelo utilizando múltiplas threads.
nomes.parallelStream()
.forEach(System.out::println);
O Java distribui automaticamente o processamento entre os núcleos do processador.
Vantagens
- Código mais legível.
- Menor quantidade de loops explícitos.
- Facilidade para filtragem e transformação de dados.
- Suporte a processamento paralelo.
- Estilo de programação funcional.
Boas Práticas
- Utilize Streams para operações de transformação de dados.
- Evite modificar variáveis externas dentro das Streams.
- Prefira métodos de referência (String::toUpperCase) quando possível.
- Utilize parallelStream() apenas após avaliar o ganho de desempenho.
- Não substitua um for simples por Streams quando a legibilidade for prejudicada.




