306 votes

Ce qui ' s le plus proche substitut pour un pointeur de fonction en Java ?

J’ai une méthode qui est à une dizaine de lignes de code. Je veux créer des méthodes plus que faire exactement la même chose, sauf pour un petit calcul qui va changer une seule ligne de code. Il s’agit d’une application parfaite pour passer un pointeur de fonction pour remplacer que d’une ligne, mais Java n’est pas des pointeurs fonction. Ce qui est ma meilleure alternative ?

272voto

sblundy Points 27163

Classe interne anonyme

Dites vous voulez avoir une fonction passée en avec un param qui retourne un .
Tout d’abord il faut définir une interface avec la fonction que son seul membre, si vous ne pouvez pas réutiliser un existant.

Une méthode qui utilise le pointeur accepterait seulement `` instance comme suit :

Et serait appelé comme suit :

32voto

Blair Conrad Points 56195

Pour chaque "pointeur de fonction", j'aimerais créer un petit foncteur de la classe qui implémente le calcul. Définir une interface que toutes les classes se mettre en œuvre, et de passer des instances de ces objets dans votre plus grande fonction. C'est une combinaison de "modèle de commande", et "modèle de stratégie".

@sblundy l'exemple est bon.

28voto

javashlook Points 4800

Lorsqu’il y a un nombre prédéfini de différents calculs, que vous pouvez le faire qu’une seule ligne, à l’aide d’un enum est un moyen rapide, encore clair moyen d’implémenter un modèle de stratégie.

De toute évidence, la déclaration de méthode de stratégie, mais aussi exactement une seule instance de chaque application est tous définis dans une classe ou un fichier unique.

24voto

rcreswick Points 6429

Vous avez besoin de créer une interface qui fournit la fonction(s) que vous souhaitez passer. par exemple:

/**
 * A simple interface to wrap up a function of one argument.
 * 
 * @author rcreswick
 *
 */
public interface Function1<S, T> {

   /**
    * Evaluates this function on it's arguments.
    * 
    * @param a The first argument.
    * @return The result.
    */
   public S eval(T a);

}

Ensuite, lorsque vous avez besoin de passer une fonction, vous pouvez implémenter cette interface:

List<Integer> result = CollectionUtilities.map(list,
        new Function1<Integer, Integer>() {
           @Override
           public Integer eval(Integer a) {
              return a * a;
           }
        });

Enfin, la fonction map utilise le passé dans Fonction1 comme suit:

   public static <K,R,S,T> Map<K, R> zipWith(Function2<R,S,T> fn, 
         Map<K, S> m1, Map<K, T> m2, Map<K, R> results){
      Set<K> keySet = new HashSet<K>();
      keySet.addAll(m1.keySet());
      keySet.addAll(m2.keySet());

      results.clear();

      for (K key : keySet) {
         results.put(key, fn.eval(m1.get(key), m2.get(key)));
      }
      return results;
   }

Vous pouvez souvent utiliser Exécutable au lieu de votre propre interface si vous n'avez pas besoin de passer des paramètres, ou vous pouvez utiliser diverses autres techniques pour faire les param comptent moins "fixe", mais il est généralement un compromis avec la sécurité de type. (Ou vous pouvez surcharger le constructeur de votre fonction de l'objet à transmettre dans les params de cette façon.. il y a beaucoup d'approches, et certains fonctionnent mieux dans certaines circonstances.)

15voto

TofuBeer Points 32441

Vous pouvez également le faire (ce qui, dans certains RARES occasions de sens). Le problème (et c'est un gros problème) c'est que vous perdez tous les typesafety de l'utilisation d'une classe ou interface et vous avez à traiter le cas où la méthode n'existe pas.

Il a l ' "avantage" que vous pouvez ignorer les restrictions d'accès et d'appeler les méthodes privées (non illustré dans l'exemple, mais vous pouvez appeler les méthodes que le compilateur ne serait pas normalement vous permettre d'appeler).

Encore une fois, c'est un cas rare que cela fait sens, mais à ces occasions, il est un outil agréable d'avoir.

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

class Main
{
    public static void main(final String[] argv)
        throws NoSuchMethodException,
               IllegalAccessException,
               IllegalArgumentException,
               InvocationTargetException
    {
        final String methodName;
        final Method method;
        final Main   main;

        main = new Main();

        if(argv.length == 0)
        {
            methodName = "foo";
        }
        else
        {
            methodName = "bar";
        }

        method = Main.class.getDeclaredMethod(methodName, int.class);

        main.car(method, 42);
    }

    private void foo(final int x)
    {
        System.out.println("foo: " + x);
    }

    private void bar(final int x)
    {
        System.out.println("bar: " + x);
    }

    private void car(final Method method,
                     final int    val)
        throws IllegalAccessException,
               IllegalArgumentException,
               InvocationTargetException
    {
        method.invoke(this, val);
    }
}

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