¿Cómo defino un método que toma un 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 debajo del capó). Hay muchos ejemplos en línea con lambdas creados y usados ​​con métodos, pero no hay ejemplos de cómo hacer que un método tome un lambda como parámetro. ¿Cuál es la syntax 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); } } 

Lambdas es simplemente una construcción de sitio de llamada: el destinatario de la lambda no necesita saber que está involucrado un Lambda, sino que acepta una interfaz con el método apropiado.

En otras palabras, define o usa una interfaz funcional (es decir, una interfaz con un único método) que acepta y devuelve exactamente lo que desea.

Para este Java 8 viene con un conjunto de tipos de interfaz de uso común en java.util.function (gracias a Maurice Naftalin por la pista sobre el JavaDoc).

Para este caso de uso específico, hay java.util.function.IntBinaryOperator con un único int applyAsInt(int left, int right) , por lo que puede escribir su method esta manera:

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

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 la operación que requiere dos enteros y devolver como valor. IntBinaryOperator

Usar la 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)); } } 

Otro ejemplo que he creado está aquí

Para funciones que no tienen más de 2 parámetros, puede pasarlos sin definir su propia interfaz. Por ejemplo,

 class Klass { static List foo(Integer a, String b) { ... } } class MyClass{ static List method(BiFunction> fn){ return fn.apply(5, "FooBar"); } } List lStr = MyClass.method((a, b) -> Klass.foo((Integer) a, (String) b)); 

En BiFunction> , Integer y String son sus parámetros, y List es su tipo de devolución.

Para una función con un solo parámetro, puede usar la Function , donde T es 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 pone a disposición.

Hay una versión pública accesible a través de la web de los JavaDad Java 8 habilitados para Lambda, enlazados desde http://lambdafaq.org/lambda-resources . (Esto obviamente debe ser un comentario sobre la respuesta de Joachim Sauer, pero no puedo ingresar a mi cuenta SO con los puntos de reputación que necesito para agregar un comentario.) El sitio lambdafaq (lo mantengo) responde a esto y a muchos otros Java -lambda preguntas.

NB Esta respuesta se escribió antes de que la documentación de Java 8 GA se hiciera pública . Sin embargo, me quedé en el lugar, porque las preguntas frecuentes de Lambda aún podrían ser útiles para las personas que están aprendiendo sobre las características introducidas en Java 8.

La expresión lambda se puede pasar como un argumento. Para pasar una expresión lambda como argumento, el tipo del parámetro (que recibe la expresión lambda como argumento) debe ser del tipo de interfaz funcional.

Si hay una interfaz funcional –

 interface IMyFunc { boolean test(int num); } 

Y hay un método de filtro que agrega el int en la lista solo si es mayor que 5. Observe que el método de filtro tiene la interfaz funcional IMyFunc como uno de los parámetros. En ese caso, la expresión lambda se puede pasar como un argumento para el parámetro de método.

 public class LambdaDemo { public static List filter(IMyFunc testNum, List listItems) { List result = new ArrayList(); for(Integer item: listItems) { if(testNum.test(item)) { result.add(item); } } return result; } public static void main(String[] args) { List myList = new ArrayList(); myList.add(1); myList.add(4); myList.add(6); myList.add(7); // calling filter method with a lambda expression // as one of the param Collection values = filter(n -> n > 5, myList); System.out.println("Filtered values " + values); } } 

Bueno, eso es fácil. El propósito de la expresión lambda es implementar la interfaz funcional. Es la interfaz con un solo método. Aquí hay un artículo de awesone sobre interfaces funcionales predefinidas y heredadas.

De todos modos, si quieres implementar tu propia interfaz funcional, hazlo. Solo por un simple ejemplo:

 public interface MyFunctionalInterface { String makeIt(String s); } 

Hagamos una clase, donde crearemos un método que acepte el tipo de MyFunctionalInterface :

 public class Main { static void printIt(String s, MyFunctionalInterface f) { System.out.println(f.makeIt(s)); } public static void main(String[] args) { } } 

Lo último que debe hacer es pasar la implementación de MyFunctionalInterface al método que hemos definido:

 public class Main { static void printIt(String s, MyFunctionalInterface f) { System.out.println(f.makeIt(s)); } public static void main(String[] args) { printIt("Java", s -> s + " is Awesome"); } } 

¡Eso es!

Lambda no es un objeto sino una interfaz funcional. Se pueden definir tantas Interfaces Funcionales como sea posible usando @FuntionalInterface como una anotación

 @FuntionalInterface public interface SumLambdaExpression { public int do(int a, int b); } public class MyClass { public static void main(String [] args) { SumLambdaExpression s = (a,b)->a+b; lambdaArgFunction(s); } public static void lambdaArgFunction(SumLambdaExpression s) { System.out.println("Output : "+s.do(2,5)); } } 

El resultado será el siguiente

 Output : 7 

El concepto básico de una expresión Lambda es definir su propia lógica pero argumentos ya definidos. Entonces, en el código anterior, puede cambiar la definición de la función do de la adición a cualquier otra definición, pero sus argumentos están limitados a 2.

Para cualquiera que esté buscando en Google esto, un buen método sería usar java.util.function.Consumer . ex:

 Import java.util.function.Consumer public Class Main { public static void runLambda(Consumer> lambda) { lambda.accept(102, 54) } public static void main(String[] args) { runLambda((int1, int2) -> System.out.println(int1 + " + " + int2 + " = " + (int1 + int2))); } 

La impresión sería: 166

Hay flexibilidad en el uso de lambda como parámetro. Permite la progtwigción funcional en Java. La syntax básica es

param -> method_body

A continuación se muestra un método, puede definir un método que tome la interfaz funcional (se usa lambda) como parámetro. a. si desea definir un método declarado dentro de una interfaz funcional, por ejemplo, la interfaz funcional se proporciona como un argumento / parámetro para un método llamado desde main()

 @FunctionalInterface interface FInterface{ int callMeLambda(String temp); } class ConcreteClass{ void funcUsesAnonymousOrLambda(FInterface fi){ System.out.println("===Executing method arg instantiated with Lambda===")); } public static void main(){ // calls a method having FInterface as an argument. funcUsesAnonymousOrLambda(new FInterface() { int callMeLambda(String temp){ //define callMeLambda(){} here.. return 0; } } } /***********Can be replaced by Lambda below*********/ funcUsesAnonymousOrLambda( (x) -> { return 0; //(1) } } 

FInterface fi = (x) -> {return 0; };

funcUsesAnonymousOrLambda (fi);

Aquí arriba se puede ver cómo una expresión lambda puede ser reemplazada por una interfaz.

Arriba explica un uso particular de la expresión lambda, hay más. ref Java 8 lambda dentro de una lambda no puede modificar la variable de la lambda externa