¿Cómo defino un método que toma una lambda como parámetro en Java 8?

Resuelto Marius asked hace 12 años • 16 respuestas

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);
  }
}
Marius avatar Nov 28 '12 19:11 Marius
Aceptado

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.IntBinaryOperatorun solo int applyAsInt(int left, int right)método , por lo que podrías escribirlo methodasí:

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.

Joachim Sauer avatar Nov 28 '2012 12:11 Joachim Sauer

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));

    }
}
pardeep131085 avatar Mar 19 '2014 15:03 pardeep131085

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>>, Integery Stringson 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 Testá su tipo de parámetro y Res su tipo de valor de retorno. Consulte esta página para conocer todas las interfaces que Java ya ofrece.

David Wu avatar May 27 '2015 03:05 David Wu

Para mí, la solución que tiene más sentido es definir una Callbackinterfaz:

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. Lambdaes 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

Mickäel A. avatar Nov 19 '2018 15:11 Mickäel A.