Uma interface funcional é definida como uma interface que não é declarada como selada (sealed) e pode conter métodos default e static mas possui exatamente um método abstrato (além dos métodos da classe Object).
Além da maneira tradicional (declarando e instanciando uma classe), instâncias de interfaces funcionais podem ser criadas de forma mais concisa utilizando expressões lambda e referências de método.
Existe ainda a anotação @FunctionalInterface que serve para indicar que uma interface deve ser funcional. Se uma interface for anotada dessa forma, mas não atender aos requisitos (como ter mais de um método abstrato), o compilador gerará um erro. No entanto, ela é opcional.
Para evitar que tenhamos que criar uma nova interface toda vez que precisarmos de uma função simples, o Java fornece um pacote padrão com as interfaces funcionais mais comuns (java.util.function). As quatro principais são:
-
Predicate<T>: Recebe um argumento e retorna umboolean.- Uso: Filtros e condicionais.
-
Método abstrato:
test(T t)
-
Consumer<T>: Recebe um argumento e não retorna nada (void).- Uso: Impressão de dados, gravação em banco, efeitos colaterais.
-
Método abstrato:
accept(T t)
-
Function<T, R>: Recebe um argumento do tipo T e retorna um resultado do tipo R.- Uso: Transformação de dados (mapeamento).
-
Método abstrato:
apply(T t)
-
Supplier<T>: Não recebe argumentos e retorna um resultado do tipo T.- Uso: Factories, geração preguiçosa (lazy) de dados.
-
Método abstrato:
get()
Exemplo prático
import java.util.function.Predicate;
// 1. Definindo uma Interface Funcional Customizada
@FunctionalInterface
interface ConversorTexto {
String converter(String texto); // Único método abstrato
// Método default não quebra a regra de interface funcional
default void imprimirLog() {
System.out.println("Executando conversão...");
}
}
public class AulaInterfaces {
public static void main(String[] args) {
// --- USO DA INTERFACE CUSTOMIZADA ---
// Implementação clássica (Classe Anônima) - O jeito antigo
ConversorTexto gritarClassico = new ConversorTexto() {
@Override
public String converter(String texto) {
return texto.toUpperCase() + "!!!";
}
};
// Implementação com Lambda - O jeito moderno
// O compilador infere que 's' é o argumento de 'converter'
ConversorTexto gritarLambda = s -> s.toUpperCase() + "!!!";
System.out.println(gritarLambda.converter("bom dia"));
// Saída: BOM DIA!!!
// --- USO DE INTERFACE PADRÃO (Predicate) ---
// Predicate verifica uma condição
Predicate<Integer> isPar = numero -> numero % 2 == 0;
validarNumero(10, isPar); // Passando comportamento como argumento
validarNumero(7, isPar);
}
// Método que aceita um comportamento (Predicate) como parâmetro
public static void validarNumero(int n, Predicate<Integer> regra) {
if (regra.test(n)) {
System.out.println(n + " passou na regra.");
} else {
System.out.println(n + " não passou na regra.");
}
}
}
Leituras Complementares
- Documentação Oficial Oracle: Pacote java.util.function.
- Livro: "Java 8 in Action" (Raoul-Gabriel Urma) - Capítulo sobre Lambdas.
- Artigo: "Functional Interfaces in Java" no Baeldung.
Top comments (0)