Equivalencia desde Kotlin
Comportamiento como valor
CercanaJava no tiene funciones de nivel superior. Para este caso se usa un método estático y una lambda cuyo tipo destino es una interfaz funcional. @FunctionalInterface no es lo que hace que una interfaz sea funcional (basta con un único método abstracto); la anotación solo hace que el compilador verifique esa propiedad.
Referencia Kotlin: Declarar una operación reutilizable y recibir otra operación como valor.
- Mecanismo
- Método
static+ interfaz funcional. Java representa el comportamiento recibido mediante una interfaz funcional, comoIntUnaryOperator. - Idea conservada
- El algoritmo depende de un comportamiento, no de su implementación.
applyTwicepuede recibir distintas lambdas o referencias a método sin conocer cómo realizan la transformación. - Riesgo de diseño
- Una lambda necesita un tipo destino. El contexto debe indicar qué interfaz funcional representa la lambda.
- Convención del curso
- Usa una interfaz de
java.util.functioncuando exprese correctamente el contrato. Declara una interfaz propia solo cuando el nombre del dominio aporte significado, por ejemploObjective<C>.
Diferencias relevantes
- El método debe pertenecer a una clase o interfaz.
- La lambda adquiere su tipo desde
IntUnaryOperator, no desde una sintaxis de tipo de función propia. - Una operación que recibe comportamiento (orden superior) usa la misma idea con otra forma de interfaz funcional, como
Predicate<T>para una condición en vez de una transformación.
La misma transformación mediante una interfaz funcional estándar.
fun applyTwice(
value: Int,
transform: (Int) -> Int,
): Int = transform(transform(value))
val result = applyTwice(3) { it + 1 } // 5package atom.functions;
import java.util.function.IntUnaryOperator;
final class ApplyTwice {
private ApplyTwice() {}
static int applyTwice(
int value,
IntUnaryOperator transform
) {
int firstResult = transform.applyAsInt(value);
return transform.applyAsInt(firstResult);
}
}El tipo destino IntUnaryOperator indica qué interfaz funcional representa la lambda.
IntUnaryOperator increment =
value -> value + 1; // Válido
var increment =
value -> value + 1; // No compilaOtra forma de interfaz funcional: un Predicate<T> recibido para filtrar una lista.
package atom.functions;
import java.util.List;
import java.util.function.Predicate;
final class Keep {
private Keep() {}
static List<Integer> keep(List<Integer> xs, Predicate<Integer> p) {
return xs.stream().filter(p).toList();
}
}Una interfaz propia aporta vocabulario cuando el contrato pertenece al dominio.
@FunctionalInterface
interface Objective<C> {
double evaluate(C candidate);
}