Streams API em Java

Introdução
Com a chegada do Java 8, a linguagem evoluiu significativamente, introduzindo conceitos da programação funcional. Entre as novidades mais marcantes está a Streams API, uma poderosa ferramenta para manipular coleções de forma declarativa, concisa e eficiente.
A Streams API permite processar dados em sequência (como listas, arrays ou coleções complexas) aplicando operações como mapeamento, filtragem, redução e combinação, tudo isso de maneira fluente e expressiva, eliminando boa parte do código imperativo tradicional com loops e condicionais.
Neste artigo, vamos explorar passo a passo desde as bases (List e Iterator) até as operações mais avançadas de Map, Filter, Reduce, Match, Min e Max, com exemplos práticos em Java.
1 – List
A interface “List” representa uma coleção ordenada de elementos que pode conter valores duplicados. É uma das coleções mais usadas em Java.
Exemplo:
import java.util.*;
public class ExemploList {
public static void main(String[] args) {
List<String> nomes = new ArrayList<>();
nomes.add("Paulo");
nomes.add("Maria");
nomes.add("Ana");
System.out.println(nomes);
}
}
Saída:
[Paulo, Maria, Ana]
2 – Iterator
Antes das Streams, o “Iterator” era a principal forma de percorrer coleções.
Exemplo:
import java.util.*;
public class ExemploIterator {
public static void main(String[] args) {
List<String> nomes = Arrays.asList("Paulo", "Maria", "Ana");
Iterator<String> iterator = nomes.iterator();
while (iterator.hasNext()) {
String nome = iterator.next();
System.out.println(nome.toUpperCase());
}
}
}
Apesar de funcional (no sentido de funcionar para o fim destinado), esse estilo é verboso e pouco expressivo, é aqui que a Streams API entra em cena.
3 – Stream
A interface “Stream<T>” permite processar coleções em pipeline, ou seja, uma sequência de operações encadeadas que transformam os dados de forma declarativa.
Exemplo:
import java.util.*;
public class ExemploStream {
public static void main(String[] args) {
List<String> nomes = Arrays.asList("Paulo", "Maria", "Ana");
nomes.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
}
}
Saida:
PAULO
MARIA
ANA
4 – Map
A operação “map()” transforma cada elemento do stream em outro valor (sem alterar o original).
Exemplo:
import java.util.*;
public class ExemploMap {
public static void main(String[] args) {
List<Integer> numeros = Arrays.asList(1, 2, 3, 4, 5);
numeros.stream()
.map(n -> n * 2)
.forEach(System.out::println);
}
}
Saída:
2
4
6
8
10
Aqui multiplicamos cada elemento por 2, sem modificar a lista original, o “map()” é excelente para transformações.
5 – Filter
A operação “filter()” permite filtrar elementos com base em uma condição booleana.
Exemplo:
import java.util.*;
public class ExemploFilter {
public static void main(String[] args) {
List<Integer> numeros = Arrays.asList(3, 6, 9, 12, 15, 18);
numeros.stream()
.filter(n -> n > 10)
.forEach(System.out::println);
}
}
Saída:
12
15
18
Aqui, apenas números maiores que 10 são exibidos.
6 – Reduce
A operação “reduce()” combina todos os elementos de um stream em um único valor, seja uma soma, multiplicação, concatenação etc.
Exemplo:
import java.util.*;
public class ExemploReduce {
public static void main(String[] args) {
List<Integer> numeros = Arrays.asList(1, 2, 3, 4, 5);
int soma = numeros.stream()
.reduce(0, (a, b) -> a + b);
System.out.println("Soma: " + soma);
}
}
Saída:
Soma: 15
O “reduce()” é muito usado em operações de agregação e estatísticas.
7 – Match
As operações anyMatch, allMatch e noneMatch permitem verificar se alguma, todas ou nenhuma condição é satisfeita pelos elementos do stream.
Exemplo:
import java.util.*;
public class ExemploMatch {
public static void main(String[] args) {
List<Integer> numeros = Arrays.asList(5, 10, 15, 20);
boolean algumMaiorQue15 = numeros.stream().anyMatch(n -> n > 15);
boolean todosPares = numeros.stream().allMatch(n -> n % 2 == 0);
boolean nenhumNegativo = numeros.stream().noneMatch(n -> n < 0);
System.out.println("Algum maior que 15? " + algumMaiorQue15);
System.out.println("Todos pares? " + todosPares);
System.out.println("Nenhum negativo? " + nenhumNegativo);
}
}
Saída:
Algum maior que 15? true
Todos pares? false
Nenhum negativo? true
8 – Min e Max
As operações min() e max() encontram, respectivamente, o menor e o maior valor de um stream.
Exemplo:
import java.util.*;
public class ExemploMinMax {
public static void main(String[] args) {
List<Integer> numeros = Arrays.asList(7, 2, 9, 4, 6);
int menor = numeros.stream().min(Integer::compareTo).get();
int maior = numeros.stream().max(Integer::compareTo).get();
System.out.println("Menor: " + menor);
System.out.println("Maior: " + maior);
}
}
Saída:
Menor: 2
Maior: 9
Conclusão
A Streams API revolucionou a forma de trabalhar com coleções no Java, permitindo que desenvolvedores escrevam códigos mais limpos, legíveis e eficientes.
Com operações como “map”, “filter” e “reduce”, é possível substituir loops complexos por pipelines funcionais elegantes, que expressam o “o que” deve ser feito, e não “como” fazer.
Além de tornar o código mais enxuto, a Streams API é otimizada para execução paralela, o que melhora a performance em grandes volumes de dados quando usada com parallelStream().
Dominar Streams API é um passo essencial para quem deseja escrever Java moderno e profissional.