Interfaces Funcionales
Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy — lección 39 de 87.
Una interfaz funcional es una interfaz que contiene exactamente un método abstracto. Esta restricción de un único método hace que las interfaces funcionales sean especiales porque pueden implementarse utilizando expresiones lambda, lo que permite un estilo de codificación más conciso.
Java proporciona la anotación @FunctionalInterface para marcar explícitamente una interfaz como funcional. Aunque es opcional, esta anotación ayuda al compilador a detectar errores si accidentalmente añades un segundo método abstracto:
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}Puedes implementar una interfaz funcional de la forma tradicional con una clase, o de forma más concisa con una expresión lambda:
// Implementación tradicional
Calculator adder = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
// Expresión lambda (¡mucho más corta!)
Calculator adder = (a, b) -> a + b;
System.out.println(adder.calculate(5, 3)); // 8Las interfaces funcionales aún pueden tener métodos predeterminados y métodos estáticos, ya que estos no cuentan para la regla del único método abstracto. El paquete java.util.function de Java proporciona muchas interfaces funcionales integradas como Predicate, Function y Consumer que encontrarás con frecuencia al trabajar con flujos y colecciones.
Desafío
FácilVamos a construir un sistema de transformación de cadenas utilizando interfaces funcionales y expresiones lambda. Crearás un procesador de texto flexible que puede aplicar diferentes transformaciones a las cadenas, todo impulsado por una única interfaz funcional.
Organizarás tu código en tres archivos:
StringTransformer.java: Define una interfaz funcional que represente cualquier operación de transformación de cadenas. Márcala con la anotación@FunctionalInterfacepara asegurar que siga siendo funcional. Tu interfaz debe declarar un único método abstracto llamadotransformque reciba un String y devuelva un String.TextProcessor.java: Crea una clase que utilice tu interfaz funcional para procesar texto. Debe tener un campo para almacenar unStringTransformery un constructor para inicializarlo. Incluye un método llamadoprocess(String text)que aplique el transformador al texto dado y devuelva el resultado. Este diseño te permite inyectar cualquier comportamiento de transformación a través del constructor.Main.java: Une todo creando diferentes transformaciones mediante expresiones lambda. Recibirás dos entradas: una cadena de texto y un tipo de operación (upper,lower, oreverse).Basándote en el tipo de operación, crea un
TextProcessorcon la lambda adecuada:upper: transforma el texto a mayúsculaslower: transforma el texto a minúsculasreverse: invierte el texto (pista: usaStringBuilder)
Luego llama a
process()con el texto de entrada e imprime el resultado en este formato:Result: [transformed text]
Recibirás dos entradas: el texto a transformar (String) y el tipo de operación (String).
Observa cómo la misma clase TextProcessor puede realizar operaciones completamente diferentes dependiendo de qué lambda le pases; ¡ese es el poder de las interfaces funcionales!
Hoja de referencia
Una interfaz funcional es una interfaz con exactamente un método abstracto. Puede implementarse utilizando expresiones lambda para obtener un código conciso.
Utilice la anotación @FunctionalInterface para marcar una interfaz como funcional (opcional pero recomendado):
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}Las interfaces funcionales pueden implementarse de forma tradicional o con expresiones lambda:
// Implementación tradicional
Calculator adder = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
// Expresión lambda
Calculator adder = (a, b) -> a + b;
System.out.println(adder.calculate(5, 3)); // 8Las interfaces funcionales pueden tener métodos predeterminados (default) y estáticos sin violar la regla del único método abstracto.
El paquete java.util.function de Java proporciona interfaces funcionales integradas como Predicate, Function y Consumer.
Pruébalo tú mismo
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: Basado en el tipo de operación, crea un TextProcessor con la lambda apropiada:
// - "upper": transforma el texto a mayúsculas
// - "lower": transforma el texto a minúsculas
// - "reverse": invierte el texto (pista: usa StringBuilder)
// TODO: Llama a process() con el texto de entrada e imprime el resultado
// Formato de salida: "Result: [transformed text]"
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosIntroducción a la OOPClases vs. ObjetosLa palabra clave thisMétodosCampos (Atributos)Método constructorSobrecarga de constructoresResumen - Calculadora simple4Herencia
Herencia básica (extends)La palabra clave superSobrescritura de métodos (@Override)Encadenamiento de constructoresLa clase ObjectHerencia simple y multinivelPor qué no hay herencia múltiple de clasesResumen - Jerarquía de empleados7Métodos especiales y la clase Object
Método toString()equals() y hashCode()Método clone()compareTo() y ComparableInterfaz ComparatorResumen - Ordenamiento personalizado2Modificadores de acceso y encapsulamiento
Visión general de los niveles de accesoMétodos Getter y SetterOcultamiento de informaciónLa palabra clave finalResumen - Gestor de cuentas bancarias5Polimorfismo
Fundamentos de sobrecarga de métodosSobrescritura de métodos (tiempo de ejecución)Upcasting y DowncastingEl operador instanceofClases y métodos abstractosResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. HerenciaAgregación vs. ComposiciónClases internas, anidadas y anónimasEnums y métodos de EnumRecords (Java 16+)Clases selladas (Java 17+)11Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón BuilderPatrón ObserverPatrón Strategy3Propiedades de clase y miembros estáticos
Variables de instancia vs. estáticasMétodos estáticosBloques estáticosConstantes (static final)Repaso - Contador y utilidad6Interfaces y Clases Abstractas
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesMétodos Default y Static en InterfacesClases Abstractas vs InterfacesInterfaces FuncionalesResumen - Sistema de Pagos9Genéricos
Introducción a los genéricosClases genéricasMétodos genéricosParámetros de tipo delimitadosComodines (?, extends, super)Resumen - Contenedor genérico12Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Iterator