lambdas - ¿Cómo defino un método que toma un lambda como parámetro en Java 8?
java 8 lambdas pdf (9)
En Java 8, los métodos se pueden crear como expresiones Lambda y se pueden pasar por referencia (con un poco de trabajo bajo el capó). Hay muchos ejemplos en línea con lambdas que se crean y utilizan 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 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);
}
}
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 impresionante sobre interfaces funcionales predefinidas y heredadas.
De todos modos, si quieres implementar tu propia interfaz funcional, hazlo. Solo por ejemplo simple:
public interface MyFunctionalInterface {
String makeIt(String s);
}
Entonces 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!
Hay flexibilidad en el uso de lambda como parámetro. Permite la programación funcional en java. La sintaxis básica es
param -> method_body
A continuación, se puede definir un método que toma la interfaz funcional (se utiliza lambda) como parámetro. a. si desea definir un método declarado dentro de una interfaz funcional, por ejemplo, la interfaz funcional se da como un argumento / parámetro a 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 se puede reemplazar una expresión lambda con una interfaz.
Arriba explica un uso particular de la expresión lambda, hay más. ref. Java 8 lambda dentro de un lambda no puede modificar la variable desde el exterior lambda
Hay una versión pública accesible desde la web de los JavaDocs Java 8 habilitados para Lambda, enlazados desde http://lambdafaq.org/lambda-resources . (Obviamente, esto debería ser un comentario sobre la respuesta de Joachim Sauer, pero no puedo acceder a mi cuenta SO con los puntos de reputación que necesito para agregar un comentario). El sitio lambdafaq (lo mantengo) responde esto y muchos otros Java -lambda preguntas.
Nota: esta respuesta se escribió antes de que la documentación de Java 8 GA se hiciera pública . Sin embargo, lo dejé en su lugar, porque las preguntas frecuentes de Lambda aún podrían ser útiles para las personas que aprenden 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 un argumento, el tipo de parámetro (que recibe la expresión lambda como un 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. Tenga en cuenta que el método de filtro tiene una 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 del método.
public class LambdaDemo {
public static List<Integer> filter(IMyFunc testNum, List<Integer> listItems) {
List<Integer> result = new ArrayList<Integer>();
for(Integer item: listItems) {
if(testNum.test(item)) {
result.add(item);
}
}
return result;
}
public static void main(String[] args) {
List<Integer> myList = new ArrayList<Integer>();
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<Integer> values = filter(n -> n > 5, myList);
System.out.println("Filtered values " + values);
}
}
Lambda no es un objeto sino una interfaz funcional. Uno puede definir tantas interfaces funcionales como puedan usar el @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));
}
}
La salida será la siguiente
Output : 7
El concepto básico de una expresión Lambda es definir su propia lógica pero argumentos ya definidos. Por lo tanto, 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.
Las Lambdas son puramente una construcción de sitio de llamada: el destinatario de la lambda no necesita saber que Lambda está involucrada, sino que acepta una Interfaz con el método apropiado.
En otras palabras, usted define o usa una interfaz funcional (es decir, una interfaz con un solo método) que acepta y devuelve exactamente lo que desea.
Para esto, 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 solo int applyAsInt(int left, int right)
, por lo que puede escribir su 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);
}
El uso de su propia interfaz tiene la ventaja de que puede tener nombres que indiquen más claramente la intención.
Para cualquiera que esté buscando en Google esto, un buen método sería utilizar java.util.function.BiConsumer
. ex:
Import java.util.function.Consumer
public Class Main {
public static void runLambda(BiConsumer<Integer, Integer> lambda) {
lambda.accept(102, 54)
}
public static void main(String[] args) {
runLambda((int1, int2) -> System.out.println(int1 + " + " + int2 + " = " + (int1 + int2)));
}
La huella sería: 166
Para usar la expresión Lambda, debe crear su propia interfaz funcional o usar la interfaz funcional de Java para operaciones que requieran dos enteros y que se devuelvan como valor. IntBinaryOperator
Usando 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á here
Para las funciones que no tienen más de 2 parámetros, puede pasarlos sin definir su 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 utilizar la Function<T, R>
, donde T
es su tipo de parámetro y R
es su tipo de valor de retorno. Consulte esta page para ver todas las interfaces que ya están disponibles en Java.