¿Cómo defino un método que toma una lambda como parámetro en Java 8?
En Java 8, los métodos se pueden crear como expresiones Lambda y se pueden pasar por referencia (con un poco de trabajo interno). Hay muchos ejemplos en línea con lambdas creadas y utilizadas con métodos, pero no hay ejemplos de cómo crear un método tomando una lambda como parámetro. ¿Cuál es la sintaxis para eso?
MyClass.method((a, b) -> a+b);
class MyClass{
//How do I define this method?
static int method(Lambda l){
return l(5, 10);
}
}
Las lambdas son puramente una construcción de sitio de llamada: el destinatario de la lambda no necesita saber que hay una lambda involucrada, sino que acepta una interfaz con el método apropiado.
En otras palabras, usted define o utiliza una interfaz funcional (es decir, una interfaz con un único método) que acepta y devuelve exactamente lo que desea.
Desde Java 8, existe un conjunto de tipos de interfaz de uso común en java.util.function
.
Para este caso de uso específico existe java.util.function.IntBinaryOperator
un solo int applyAsInt(int left, int right)
método , por lo que podrías escribirlo method
así:
static int method(IntBinaryOperator op){
return op.applyAsInt(5, 10);
}
Pero también puedes definir tu propia interfaz y usarla así:
public interface TwoArgIntOperator {
public int op(int a, int b);
}
//elsewhere:
static int method(TwoArgIntOperator operator) {
return operator.op(5, 10);
}
Luego llame al método con una lambda como parámetro:
public static void main(String[] args) {
TwoArgIntOperator addTwoInts = (a, b) -> a + b;
int result = method(addTwoInts);
System.out.println("Result: " + result);
}
Usar su propia interfaz tiene la ventaja de que puede tener nombres que indiquen más claramente la intención.
Para usar la expresión Lambda, necesita crear su propia interfaz funcional o usar la interfaz funcional de Java para operaciones que requieren dos números enteros y devolverlos como valor. OperadorIntBinario
Usando una interfaz funcional definida por el usuario
interface TwoArgInterface {
public int operation(int a, int b);
}
public class MyClass {
public static void main(String javalatte[]) {
// this is lambda expression
TwoArgInterface plusOperation = (a, b) -> a + b;
System.out.println("Sum of 10,34 : " + plusOperation.operation(10, 34));
}
}
Usando la interfaz funcional de Java
import java.util.function.IntBinaryOperator;
public class MyClass1 {
static void main(String javalatte[]) {
// this is lambda expression
IntBinaryOperator plusOperation = (a, b) -> a + b;
System.out.println("Sum of 10,34 : " + plusOperation.applyAsInt(10, 34));
}
}
Para funciones que no tienen más de 2 parámetros, puedes pasarlos sin definir tu propia interfaz. Por ejemplo,
class Klass {
static List<String> foo(Integer a, String b) { ... }
}
class MyClass{
static List<String> method(BiFunction<Integer, String, List<String>> fn){
return fn.apply(5, "FooBar");
}
}
List<String> lStr = MyClass.method((a, b) -> Klass.foo((Integer) a, (String) b));
En BiFunction<Integer, String, List<String>>
, Integer
y String
son sus parámetros, y List<String>
es su tipo de retorno.
Para una función con un solo parámetro, puede usar Function<T, R>
, donde T
está su tipo de parámetro y R
es su tipo de valor de retorno. Consulte esta página para conocer todas las interfaces que Java ya ofrece.
Para mí, la solución que tiene más sentido es definir una Callback
interfaz:
interface Callback {
void call();
}
y luego usarlo como parámetro en la función que desea llamar:
void somewhereInYourCode() {
method(() -> {
// You've passed a lambda!
// method() is done, do whatever you want here.
});
}
void method(Callback callback) {
// Do what you have to do
// ...
// Don't forget to notify the caller once you're done
callback.call();
}
Aunque solo una precisión
Una lambda no es una interfaz, clase o cualquier otra cosa especial que pueda declarar usted mismo. Lambda
es solo el nombre dado a la () -> {}
sintaxis especial, que permite una mejor legibilidad al pasar interfaces de método único como parámetro. Fue diseñado para reemplazar esto:
method(new Callback() {
@Override
public void call() {
// Classic interface implementation, lot of useless boilerplate code.
// method() is done, do whatever you want here.
}
});
Entonces, en el ejemplo anterior, noCallback
es una lambda, es solo una interfaz normal; es el nombre de la sintaxis de acceso directo que puede utilizar para implementarlo.lambda