Expressões Lambda e as Quatro Interfaces Funcionais no Java 8

Introduzido no Java 8, as expressões lambda representam uma forma concisa de definir funções anônimas. Esta característica, juntamente com as interfaces funcionais, transforma a forma como o código é escrito, promovendo uma programação mais funcional e declarativa.

Sintaxe Básica das Expressões Lambda

Uma expressão lambda é definida por uma lista de parâmetros, seguida pelo operador seta (->) e um corpo. Se o corpo contiver uma única instrução, as chaves e a palavra-chave return podem ser omitidas. O compilador frequentemente infere os tipos dos parâmetros, tornando o código mais limpo.

Exemplos de formas válidas:

// Sem parâmetros
() -> System.out.println("Executando tarefa");

// Um único parâmetro (parênteses opcionais)
mensagem -> System.out.println(mensagem);

// Dois parâmetros com retorno explícito
(a, b) -> {
    int resultado = a + b;
    return resultado;
};

// Dois parâmetros com retorno implícito
(a, b) -> a + b;

Regras de Sintaxe

  • Zero ou mais parâmetros são permitidos.
  • Com um único parâmetro e tipo inferido, os parênteses são opcionais.
  • O corpo pode ser uma única expressão ou um bloco de código entre chaves.
  • Para múltiplas instruções no corpo, as chaves são obrigatórias e um return explícito é necessário se houver valor de retorno.

Interfaces Funcionais

Uma interface funcional é uma interface com exatamente um método abstrato. As expressões lambda só podem ser usadas em contextos que esperam uma interface funcional. A anotação @FunctionalInterface pode ser usada para garantir essa restrição em tempo de compilação.

@FunctionalInterface
public interface TransformadorString {
    String aplicar(String texto);
}

Exemplo de uso com uma expressão lambda:

TransformadorString paraMaiusculas = s -> s.toUpperCase();
String resultado = paraMaiusculas.aplicar("java oito"); // "JAVA OITO"

Interfaces Funcionais Embutidas no Java 8

A biblioteca padrão fornece quatro interfaces funcionais genéricas fundamentais, localizadas no pacote java.util.function.

1. Consumer<T> - Consumidor

Representa uma operação que aceita um único argumento e não retorna resultado. É usado para produzir efeitos colaterais.

// Assinatura do método
void accept(T t);

// Exemplo de uso
Consumer<String> impressora = texto -> System.out.println("Log: " + texto);
impressora.accept("Operação concluída");

2. Supplier<T> - Fornecedor

Representa uma operação que não aceita argumentos e retorna um resultado. É usado para gerar ou fornecer valores.

// Assinatura do método
T get();

// Exemplo: Gerador de números aleatórios
Supplier<Double> geradorAleatorio = () -> Math.random();
Double valor = geradorAleatorio.get();

3. Function<T, R> - Função

Representa uma função que aceita um argumento do tipo T e produz um resultado do tipo R.

// Assinatura do método
R apply(T t);

// Exemplo: Converter String para seu tamanho
Function<String, Integer> calcularComprimento = s -> s.length();
int tamanho = calcularComprimento.apply("Lambda"); // 6

4. Predicate<T> - Predicado

Representa uma função que aceita um argumento do tipo T e retorna um valor booleano. É frequentemente usado para filtragem.

// Assinatura do método
boolean test(T t);

// Exemplo: Verificar se um número é par
Predicate<Integer> ehPar = numero -> numero % 2 == 0;
boolean teste = ehPar.test(4); // true

Exemplo Prático: Filtragem com Predicate

Abaixo, uma lista de palavras é filtrada para manter apenas as que têm mais de cinco caracteres.

List<String> palavras = Arrays.asList("lambda", "expressão", "java", "interface");
Predicate<String> comprimentoMaiorQueCinco = p -> p.length() > 5;

List<String> palavrasLongas = new ArrayList<>();
for (String palavra : palavras) {
    if (comprimentoMaiorQueCinco.test(palavra)) {
        palavrasLongas.add(palavra);
    }
}
// Resultado: ["lambda", "expressão", "interface"]

Composição de Interfaces Funcionais

Essas interfaces possuem métodos padrão (como andThen, compose, negate) que permitem combinar operações, criando pipelines de processamento complexos de forma elegante.

Function<String, String> removerEspacos = s -> s.trim();
Function<String, String> converterMinusculas = s -> s.toLowerCase();

// Composição: primeiro remove espaços, depois converte para minúsculas
Function<String, String> limparEFormatar = removerEspacos.andThen(converterMinusculas);

String resultado = limparEFormatar.apply("   JAVA 8 "); // "java 8"

Tags: Java 8 Expressões Lambda Interfaces Funcionais Consumer Supplier

Publicado em 7-10 01:13