Comment définir une méthode qui prend un lambda comme paramètre dans Java 8?


En Java 8, les méthodes peuvent être créées en tant qu'expressions Lambda et peuvent être passées par référence (avec un peu de travail sous le capot). Il existe de nombreux exemples en ligne avec des lambdas créés et utilisés avec des méthodes, mais aucun exemple sur la façon de créer une méthode prenant un lambda comme paramètre. Quelle est la syntaxe pour cela?

MyClass.method((a, b) -> a+b);


class MyClass{
  //How do I define this method?
  static int method(Lambda l){
    return l(5, 10);
  }
}
Author: Jan Nielsen, 2012-11-28

14 answers

Les lambdas sont purement une construction de site d'appel: le destinataire du lambda n'a pas besoin de savoir qu'un Lambda est impliqué, il accepte plutôt une interface avec la méthode appropriée.

En d'autres termes, vous définissez ou utiliser une interface fonctionnelle (c'est à dire une interface avec une seule méthode) qui accepte et renvoie exactement ce que vous voulez.

Pour cela Java 8 est livré avec un ensemble de types d'interface couramment utilisés dans java.util.function (merci à Maurice Naftalin pour l'indice à propos du JavaDoc).

Pour ce cas d'utilisation spécifiques il y a java.util.function.IntBinaryOperator avec la seule int applyAsInt(int left, int right) méthode, de sorte que vous pouvez écrire votre method comme ceci:

static int method(IntBinaryOperator op){
    return op.applyAsInt(5, 10);
}

, Mais vous pouvez tout aussi bien définir votre propre interface et de l'utiliser comme ceci:

public interface TwoArgIntOperator {
    public int op(int a, int b);
}

//elsewhere:
static int method(TwoArgIntOperator operator) {
    return operator.op(5, 10);
}

L'utilisation de votre propre interface a l'avantage d'avoir des noms qui indiquent plus clairement l'intention.

 261
Author: Joachim Sauer, 2017-05-23 11:55:10

Pour utiliser l'expression Lambda, vous devez soit créer votre propre interface fonctionnelle, soit utiliser l'interface fonctionnelle Java pour les opérations nécessitant deux entiers et retourner en tant que valeur. IntBinaryOperator

Utilisation de l'interface fonctionnelle définie par l'utilisateur

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

    }
}

Utilisation de l'interface fonctionnelle 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));

    }
}
 67
Author: pardeep131085, 2020-10-31 14:20:06

Pour les fonctions qui n'ont pas plus de 2 paramètres, vous pouvez les passer sans définir votre propre interface. Par exemple,

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

Dans BiFunction<Integer, String, List<String>>, Integer et String sont ses paramètres, et List<String> est son type de retour.

, Pour une fonction avec un seul paramètre, vous pouvez utiliser Function<T, R>, où T est son paramètre de type, et R est sa valeur de retour de type. Reportez-vous à cette page pour toutes les interfaces qui sont déjà mis à disposition par Java.

 38
Author: David Wu, 2015-05-27 03:19:32

Il existe une version publique accessible sur le Web des JavaDocs Java 8 compatibles Lambda, liée à partir de http://lambdafaq.org/lambda-resources. (Cela devrait évidemment être un commentaire sur la réponse de Joachim Sauer, mais je ne peux pas entrer dans mon compte SO avec les points de réputation dont j'ai besoin pour ajouter un commentaire.) Le site lambdafaq (je le maintiens) répond à cela et à beaucoup d'autres questions Java-lambda.

NB Cette réponse a été écrite avant que la documentation Java 8 GA ne devienne publique disponible. J'ai laissé en place, cependant, parce que laLambda FAQ pourrait toujours être utile aux personnes qui apprennent sur les fonctionnalités introduites dans Java 8.

 15
Author: Maurice Naftalin, 2018-06-14 09:27:52

Pour moi, la solution qui a le plus de sens est de définir une interface Callback:

interface Callback {
    void call();
}

, puis de l'utiliser comme paramètre dans la fonction que vous voulez l'appeler :

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

Juste une précision cependant

Un lambda n'est pas une interface spéciale, une classe ou toute autre chose que vous pourriez déclarer par vous-même. Lambda est juste le nom donné à la syntaxe spéciale () -> {}, qui permet une meilleure lisibilité lors du passage d'interfaces à méthode unique en tant que paramètre. Il a été conçu pour remplacer cela :

method(new Callback() {
    @Override
    public void call() {
        // Classic interface implementation, lot of useless boilerplate code.
        // method() is done, do whatever you want here.
    }
});

Donc dans l'exemple ci-dessus, Callbackest pas un lambda, c'est juste une interface régulière ; lambda est le nom de la syntaxe de raccourci que vous pouvez utiliser pour l'implémenter.

 9
Author: flawyte, 2018-11-19 15:32:05

L'expression Lambda peut être passée comme un argument.To passer une expression lambda en tant qu'argument le type du paramètre (qui reçoit l'expression lambda en tant qu'argument) doit être de type d'interface fonctionnelle.

S'il existe une interface fonctionnelle -

interface IMyFunc {
   boolean test(int num);
}

Et il existe une méthode de filtre qui ajoute l'int dans la liste uniquement s'il est supérieur à 5. Notez ici que la méthode filter a l'interface funtional IMyFunc comme l'un des paramètres. Dans ce cas l'expression lambda peut être passé comme argument pour le paramètre de méthode.

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);
    }
}
 7
Author: infoj, 2017-01-29 15:22:09

Pour quiconque recherche cela sur Google, une bonne méthode serait d'utiliser 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)));
    }

L'outprint serait: 166

 7
Author: Big_Bad_E, 2018-10-11 00:00:59

Lambda n'est pas un objet mais une Interface fonctionnelle. On peut définir autant d'interfaces fonctionnelles que possible en utilisant @FuntionalInterface comme une annotation

@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 sortie sera la suivante

Output : 7

Le concept de base d'une Expression Lambda est de définir votre propre logique mais des arguments déjà définis. Donc, dans le code ci-dessus, vous pouvez modifier la définition de la fonction do d'addition à toute autre définition, mais vos arguments sont limités à 2.

 4
Author: raja emani, 2018-06-04 09:56:14

Vous pouvez utiliser des interfaces fonctionnelles comme mentionné ci-dessus. voici quelques exemples

Function<Integer, Integer> f1 = num->(num*2+1);
System.out.println(f1.apply(10));

Predicate<Integer> f2= num->(num > 10);
System.out.println(f2.test(10));
System.out.println(f2.test(11));

Supplier<Integer> f3= ()-> 100;
System.out.println(f3.get());

J'espère que ça aide

 4
Author: ank, 2019-10-22 15:54:43

Fondamentalement, pour passer une expression lamda en tant que paramètre, nous avons besoin d'un type dans lequel nous pouvons la contenir. Tout comme une valeur entière que nous détenons dans la primitive int ou la classe Integer. Java n'a pas de type séparé pour l'expression lamda à la place, il utilise une interface comme type pour contenir l'argument. Mais cette interface devrait être une interface fonctionnelle .

 3
Author: Vamshi, 2019-05-10 07:32:25

Eh Bien, c'est facile. Le but de l'expression lambda est d'implémenter une interface fonctionnelle. Il est l'interface avec une seule méthode. Voici un article awesone sur les interfaces fonctionnelles prédéfinies et héritées.

Quoi qu'il en soit, si vous voulez implémenter votre propre interface fonctionnelle, faites-la. Juste pour un exemple simple:

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

Faisons donc une classe, où nous allons créer une méthode, qui accepte le type de MyFunctionalInterface :

public class Main {

    static void printIt(String s, MyFunctionalInterface f) {
        System.out.println(f.makeIt(s));
    }

    public static void main(String[] args) {

    }
}

Le dernier la chose que vous devez faire est de passer l'implémentation du MyFunctionalInterface à la méthode que nous avons définie:

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

C'est tout!

 1
Author: SanchelliosProg, 2018-04-20 05:46:21

Procédez comme suit ..

Vous avez déclaré method(lambda l) Tout ce que vous voulez faire est de créer une interface avec le nom lambda et de déclarer une méthode abstraite

public int add(int a,int b);  

Le nom de la méthode n'a pas d'importance ici..

Donc quand vous appelez MyClass.method( (a,b)->a+b) Cette implémentation (a,b)->a+b sera injectée dans votre interface add method .Donc, chaque fois que vous appelez l.add, elle va prendre cette implémentation et effectuer l'ajout de a et b et return l.add(2,3) retournera 5. - Fondamentalement, c'est ce lambda faire..

 0
Author: Arasn, 2019-04-20 10:30:44

Voici à peu près comment C# gère ce problème (mais exprimé en code Java). Quelque chose comme ça pourrait gérer presque tous vos besoins:

import static org.util.function.Functions.*;

public class Test {

    public static void main(String[] args)
    {
        Test.invoke((a, b) -> a + b);       
    }

    public static void invoke(Func2<Integer, Integer, Integer> func)
    {
        System.out.println(func.apply(5, 6));
    }
}

package org.util.function;

public interface Functions {

    //Actions:
    public interface Action {
        public void apply();
    }

    public interface Action1<T1> {
        public void apply(T1 arg1);
    }

    public interface Action2<T1, T2> {
        public void apply(T1 arg1, T2 arg2);
    }

    public interface Action3<T1, T2, T3> {
        public void apply(T1 arg1, T2 arg2, T3 arg3);
    }

    public interface Action4<T1, T2, T3, T4> {
        public void apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
    }

    public interface Action5<T1, T2, T3, T4, T5> {
        public void apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
    }

    public interface Action6<T1, T2, T3, T4, T5, T6> {
        public void apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
    }

    public interface Action7<T1, T2, T3, T4, T5, T6, T7> {
        public void apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
    }

    public interface Action8<T1, T2, T3, T4, T5, T6, T7, T8> {
        public void apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
    }

    //Functions:
    public interface Func<TResult> {
        public TResult apply();
    }

    public interface Func1<T1, TResult> {
        public TResult apply(T1 arg1);
    }

    public interface Func2<T1, T2, TResult> {
        public TResult apply(T1 arg1, T2 arg2);
    }

    public interface Func3<T1, T2, T3, TResult> {
        public TResult apply(T1 arg1, T2 arg2, T3 arg3);
    }

    public interface Func4<T1, T2, T3, T4, TResult> {
        public TResult apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
    }

    public interface Func5<T1, T2, T3, T4, T5, TResult> {
        public TResult apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
    }

    public interface Func6<T1, T2, T3, T4, T5, T6, TResult> {
        public TResult apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
    }

    public interface Func7<T1, T2, T3, T4, T5, T6, T7, TResult> {
        public TResult apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
    }

    public interface Func8<T1, T2, T3, T4, T5, T6, T7, T8, TResult> {
        public TResult apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
    }
}
 -1
Author: craigrs84, 2020-06-02 17:47:19

Il y a de la flexibilité dans l'utilisation de lambda comme paramètre. Il permet la programmation fonctionnelle en java. La syntaxe de base est

Param - > method_body

Voici un moyen, vous pouvez définir une méthode prenant l'interface fonctionnelle (lambda est utilisé) comme paramètre. a. si vous souhaitez définir une méthode déclarée dans une interface fonctionnelle, disons que l'interface fonctionnelle est donnée en tant qu'argument / paramètre à une méthode appelée depuis 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) - >{retour 0;};

FuncUsesAnonymousOrLambda (fi);

Ici ci-dessus, on peut voir comment une expression lambda peut être remplacée par une interface.

Ci-dessus explique un usage particulier de l'expression lambda, il y en a plus. ref Java 8 lambda dans un lambda ne peut pas modifier la variable de lambda externe

 -2
Author: hi.nitish, 2020-06-20 09:12:55