Interfaces Funcionais
Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 39 de 87.
Uma interface funcional é uma interface que contém exatamente um método abstrato. Essa restrição de método único torna as interfaces funcionais especiais porque elas podem ser implementadas usando expressões lambda, permitindo um estilo de codificação mais conciso.
O Java fornece a anotação @FunctionalInterface para marcar explicitamente uma interface como funcional. Embora opcional, essa anotação ajuda o compilador a capturar erros se você acidentalmente adicionar um segundo método abstrato:
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}Você pode implementar uma interface funcional da maneira tradicional com uma classe, ou de forma mais concisa com uma expressão lambda:
// Implementação tradicional
Calculator adder = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
// Expressão lambda (muito mais curta!)
Calculator adder = (a, b) -> a + b;
System.out.println(adder.calculate(5, 3)); // 8Interfaces funcionais ainda podem ter métodos default e métodos estáticos, já que eles não contam para a regra do único método abstrato. O pacote java.util.function do Java fornece muitas interfaces funcionais integradas como Predicate, Function e Consumer que você encontrará frequentemente ao trabalhar com streams e coleções.
Desafio
FácilVamos construir um sistema de transformação de strings usando interfaces funcionais e expressões lambda. Você criará um processador de texto flexível que pode aplicar diferentes transformações a strings—tudo alimentado por uma única interface funcional.
Você organizará seu código em três arquivos:
StringTransformer.java: Defina uma interface funcional que represente qualquer operação de transformação de string. Marque-a com a anotação@FunctionalInterfacepara garantir que ela permaneça funcional. Sua interface deve declarar um único método abstrato chamadotransformque recebe uma String e retorna uma String.TextProcessor.java: Crie uma classe que use sua interface funcional para processar texto. Ela deve ter um campo para armazenar umStringTransformere um construtor para inicializá-lo. Inclua um método chamadoprocess(String text)que aplica o transformador ao texto fornecido e retorna o resultado. Este design permite injetar qualquer comportamento de transformação através do construtor.Main.java: Reúna tudo criando diferentes transformações usando expressões lambda. Você receberá duas entradas: uma string de texto e um tipo de operação (upper,lower, oureverse).Com base no tipo de operação, crie um
TextProcessorcom a lambda apropriada:upper: transforma o texto em maiúsculaslower: transforma o texto em minúsculasreverse: inverte o texto (dica: useStringBuilder)
Em seguida, chame
process()com o texto de entrada e imprima o resultado neste formato:Result: [transformed text]
Você receberá duas entradas: o texto a ser transformado (String) e o tipo de operação (String).
Observe como a mesma classe TextProcessor pode realizar operações completamente diferentes dependendo de qual lambda você passa—esse é o poder das interfaces funcionais!
Folha de consulta
Uma interface funcional é uma interface com exatamente um método abstrato. Ela pode ser implementada usando expressões lambda para um código conciso.
Use a anotação @FunctionalInterface para marcar uma interface como funcional (opcional, mas recomendado):
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}Interfaces funcionais podem ser implementadas tradicionalmente ou com expressões lambda:
// Implementação tradicional
Calculator adder = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
// Expressão lambda
Calculator adder = (a, b) -> a + b;
System.out.println(adder.calculate(5, 3)); // 8Interfaces funcionais podem ter métodos default e estáticos sem violar a regra de um único método abstrato.
O pacote java.util.function do Java fornece interfaces funcionais integradas como Predicate, Function e Consumer.
Experimente você mesmo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String text = scanner.nextLine();
String operation = scanner.nextLine();
TextProcessor processor;
// TODO: Com base no tipo de operação, crie um TextProcessor com a lambda apropriada:
// - "upper": transforma o texto em maiúsculas
// - "lower": transforma o texto em minúsculas
// - "reverse": inverte o texto (dica: use StringBuilder)
// TODO: Chame process() com o texto de entrada e imprima o resultado
// Formato de saída: "Result: [transformed text]"
}
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave thisMétodosCampos (Atributos)Método ConstrutorSobrecarga de ConstrutorRecapitulação - Calculadora Simples4Herança
Herança Básica (extends)A Palavra-chave superSobrescrita de Método (@Override)Encadeamento de ConstrutoresA Classe ObjectHerança Simples e MultinívelPor que não há Herança Múltipla de ClassesRecapitulação - Hierarquia de Funcionários7Métodos Especiais e a Classe Object
Método toString()equals() e hashCode()Método clone()compareTo() e ComparableInterface ComparatorRecapitulação - Ordenação Personalizada2Modificadores de Acesso e Encapsulamento
Visão Geral dos Níveis de AcessoMétodos Getter e SetterOcultação de InformaçõesA Palavra-chave finalRecapitulação - Gerenciador de Conta Bancária5Polimorfismo
Fundamentos de Sobrecarga de MétodosSobrescrita de Métodos (Tempo de Execução)Upcasting e DowncastingO Operador instanceofClasses e Métodos AbstratosRecapitulação - Calculadora de Formas8Conceitos Avançados de OOP
Composição vs HerançaAgregação vs ComposiçãoClasses Internas, Aninhadas e AnônimasEnums e Métodos de EnumRecords (Java 16+)Classes Seladas (Java 17+)11Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão BuilderPadrão ObserverPadrão Strategy3Propriedades de Classe e Membros Estáticos
Variáveis de Instância vs EstáticasMétodos EstáticosBlocos EstáticosConstantes (static final)Recapitulação - Contador e Utilitário6Interfaces e Classes Abstratas
Introdução às InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesDefault e Static em InterfacesClasses Abstratas vs InterfacesInterfaces FuncionaisRecapitulação - Sistema de Pagamento9Generics
Introdução a GenericsClasses GenéricasMétodos GenéricosParâmetros de Tipos DelimitadosWildcards (?, extends, super)Recapitulação - Container Genérico12Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Iterator