Programação Funcional em Java: de Lambdas ao Stream API

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Programação Funcional em Java: de Lambdas ao Stream API



Programação Funcional (PF) é um paradigma no qual os cálculos são representados como avaliação de funções matemáticas, evitando a mudança de estado e a mutação de dados. Por muito tempo, Java permaneceu uma linguagem estritamente orientada a objetos, mas com o lançamento do Java 8 (2014), deu um enorme passo em direção à PF, adicionando expressões lambda, interfaces funcionais e o Stream API. Hoje, essas ferramentas são indispensáveis para escrever código conciso, legível e seguro para paralelismo.



Neste artigo, vamos explorar os conceitos-chave da programação funcional em Java: desde os fundamentos das lambdas até o processamento avançado de coleções com o Stream API. O material é voltado para desenvolvedores que já conhecem a sintaxe básica do Java, mas desejam dominar abordagens modernas.



1. Expressões Lambda e Interfaces Funcionais



Uma expressão lambda é uma função anônima (um método sem nome) que pode ser passada como argumento ou armazenada em uma variável. Em Java, uma lambda implementa uma interface funcional — uma interface com exatamente um método abstrato (SAM — Single Abstract Method).



Sintaxe:

(parâmetros) -> { corpo }


Exemplo: em vez de criar uma classe anônima para um comparador:

// Jeito antigo (Java 7)Comparator<String> comparator = new Comparator<String>() {    @Override    public int compare(String s1, String s2) {        return s1.length() - s2.length();    }};

// Jeito novo (Java 8+)Comparator<String> comparatorLambda = (s1, s2) -> s1.length() - s2.length();


Principais interfaces funcionais em Java (pacote java.util.function):

  • Predicate<T> — verifica uma condição (método test).
  • Function<T, R> — transforma um objeto do tipo T em R (método apply).
  • Consumer<T> — executa uma ação sobre um objeto (método accept).
  • Supplier<T> — fornece um objeto sem parâmetros de entrada (método get).


Exemplo com Predicate:

Predicate<Integer> isEven = n -> n % 2 == 0;System.out.println(isEven.test(4)); // trueSystem.out.println(isEven.test(5)); // false


Referências a Métodos (Method References) — são uma forma abreviada de escrever lambdas quando o corpo consiste em uma única chamada de método:

// Lambdalist.forEach(item -> System.out.println(item));// Referência a métodolist.forEach(System.out::println);


2. Stream API: Operações Básicas



O Stream API é uma ferramenta poderosa para processar sequências de dados (coleções, arrays, arquivos) de forma declarativa. Um Stream não armazena dados, apenas descreve um pipeline de operações. Os dados não são modificados — cada etapa cria um novo stream.



Criação de um Stream:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");Stream<String> stream = names.stream(); // sequencialStream<String> parallelStream = names.parallelStream(); // paralelo


Operações intermediárias (retornam um novo Stream):

  • filter(Predicate) — seleciona elementos com base em uma condição.
  • map(Function) — transforma cada elemento.
  • sorted() / sorted(Comparator) — ordenação.
  • distinct() — remove duplicatas.
  • limit(n) — limita o número de elementos.


Operações terminais (finalizam o stream, retornam um resultado):

  • collect(Collectors.toList()) — coleta em uma coleção.
  • forEach(Con

Blogs

Book Recommendations