494 votes

Comment passer une fonction comme paramètre dans Java ?

Est-il possible de passer d’une méthode dans une méthode Java en tant que paramètre ? Dans l’affirmative, pourrait quelqu'un s’il vous plaît me guider ? Cela ne semble pas trivial

565voto

jk. Points 2255

Remarque: La réponse suivante suffit pour les versions de Java AVANT de Java 8. Si vous êtes à l'aide de Java 8, recherchez "java 8 les expressions lambda'. Il est sucre syntaxique pour ce que je décris ci-dessous.

Un modèle commun serait de "wrap" il au sein d'une interface, Callable, par exemple, puis vous passez dans un Callable:

public T myMethod(Callable<T> func) {
    return func.call();
}

Ce modèle est connu comme le Modèle de Commande.

Gardez à l'esprit que vous avez, le mieux serait de créer une interface pour votre usage particulier. Si vous avez choisi d'aller avec appelable, vous devez alors remplacer T ci-dessus avec quel que soit le type de valeur de retour vous attendent, tels que la Chaîne.

En réponse à votre commentaire ci-dessous, on pourrait dire:

public int methodToPass() { 
        // do something
}

public void dansMethod(int i, Callable<Integer> myFunc) {
       // do something
}

ensuite l'appeler, peut-être l'aide d'un anonyme intérieur de la classe:

dansMethod(100, new Callable<Integer>() {
   public Integer call() {
        return methodToPass();
   }
});

Gardez à l'esprit que ce n'est pas un "truc". C'est juste de java de base équivalent conceptuel à des pointeurs de fonction.

129voto

Blaise Doughan Points 75613

Vous pouvez utiliser la réflexion de Java pour cela. La méthode serait représentée comme une instance de java.lang.reflect.Method.

101voto

Pour ajouter à jk.'s excellente réponse, vous pouvez maintenant passer à une méthode plus facilement en utilisant les Expressions Lambda (Java 8). Tout d'abord, un peu de fond. Une interface fonctionnelle est une interface qui a une et une seule méthode abstraite, même si elle peut contenir n'importe quel nombre de méthodes par défaut (nouveau dans Java 8) et des méthodes statiques. Une expression lambda peut rapidement mettre en place la méthode abstraite, sans tous les inutiles syntaxe est nécessaire si vous n'utilisez pas une expression lambda.

Sans expressions lambda:

obj.aMethod(new AFunctionalInterface() {
    @Override
    public boolean anotherMethod(int i)
    {
        return i == 982
    }
});

Avec les expressions lambda:

obj.aMethod(i -> i == 982);

Voici un extrait de la Java tutoriel sur les Expressions Lambda:

La syntaxe des Expressions Lambda

Une expression lambda se compose des éléments suivants:

  • Une liste séparée par des virgules des paramètres formels entre parenthèses. Le CheckPerson.la méthode d'essai contient un paramètre, p, ce qui représente une instance de la classe Personne.

    Remarque: Vous pouvez omettre le type de données de paramètres dans une expression lambda. Dans outre, vous pouvez omettre les parenthèses si il y a un seul paramètre. Par exemple, la lambda expression est aussi valable:

    p -> p.getGender() == Person.Sex.MALE 
        && p.getAge() >= 18
        && p.getAge() <= 25
    
  • La flèche jeton, ->

  • Un corps, qui consiste en une seule expression ou un bloc d'instructions. Cet exemple utilise l'expression suivante:

    p.getGender() == Person.Sex.MALE 
        && p.getAge() >= 18
        && p.getAge() <= 25
    

    Si vous spécifiez une expression unique, puis le Java runtime évalue l'expression et retourne ensuite à sa valeur. Sinon, vous pouvez utiliser une instruction de retour:

    p -> {
        return p.getGender() == Person.Sex.MALE
            && p.getAge() >= 18
            && p.getAge() <= 25;
    }
    

    Une instruction return n'est pas une expression, une expression lambda, vous devez joindre les rapports entre accolades ({}). Cependant, vous n'avez pas pour joindre un spécimen de l'invocation de méthode dans des accolades. Par exemple, l' suivant est valide expression lambda:

    email -> System.out.println(email)
    

Notez qu'une lambda expression ressemble un peu comme une déclaration de méthode; vous pouvez considérer les expressions lambda anonyme méthodes sans nom.


Voici comment vous pouvez "passer d'une méthode" à l'aide d'une expression lambda:

Remarque: cette fonction utilise un nouveau standard d'interface fonctionnelle, java.util.function.IntConsumer.

class A
{
    public static void methodToPass(int i)
    { 
        //do stuff
    }
}


import java.util.function.IntConsumer;
class B
{
    public void dansMethod(int i, IntConsumer aFunction)
    {
       //do stuff
    }
}


class C
{
    B b = new B();

    public C(int i)
    {
        b.dansMethod(100, i -> A.methodToPass(i));   //Lambda Expression here
    }
}

L'exemple ci-dessus peut être raccourcie d'autant plus à l'aide de l' :: de l'opérateur.

public C(int i)
{
    b.dansMethod(100, A::methodToPass);
}

Avertissement: je ne peux pas exécuter Java 8 sur mon ordinateur, car il ne prend pas en charge Windows XP. L'un des exemples inclus dans cette réponse peut y avoir des erreurs, en raison de ne pas être en mesure de les tester.

17voto

Nathan Hughes Points 30377

En général, vous déclarez votre méthode que la prise en interface avec une seule méthode, puis vous passez un objet qui implémente cette interface. Un exemple est dans commons-collections, où vous avez des interfaces pour la Fermeture, Transformateur, et le Prédicat, et les méthodes que vous passez implémentations de ces dans. La goyave est le nouveau et amélioré commons-collections, vous pouvez trouver l'équivalent des interfaces.

Ainsi, par exemple, commons-collections a org.apache.commons.les collections.CollectionUtils, qui a beaucoup de méthodes statiques que prendre des objets transmis, d'en choisir un au hasard, il y a un appelé existe avec cette signature:

static boolean exists(java.util.Collection collection, Predicate predicate) 

Il prend un objet qui implémente l'interface Prédicat, ce qui signifie qu'il doit avoir une méthode qui prend un Objet et retourne un booléen.

Donc, je peux l'appeler comme ceci:

CollectionUtils.exists(someCollection, new Predicate() {
    public boolean evaluate(Object object) { 
        return (object.toString() == "a");
    }
});

et elle retourne true ou false selon que someCollection contient un objet que le prédicat renvoie la valeur true.

De toute façon, c'est juste un exemple, et commons-collections est obsolète. J'ai juste oublier l'équivalent dans la Goyave.

6voto

amalloy Points 29125

Java supporte bien les fermetures. Il ne supporte pas les fonctions , donc la syntaxe à laquelle vous êtes habitué pour les fermetures est beaucoup plus gênante et encombrante: vous devez tout emballer dans une classe avec une méthode. Par exemple,

 public Runnable foo(final int x) {
  return new Runnable() {
    public void run() {
      System.out.println(x);
    }
  };
}
 

Renvoie un objet Runnable dont la méthode run() "se referme" sur le x transmis, comme dans tout langage prenant en charge des fonctions et des fermetures de première classe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X