J'ai une méthode qui fait environ dix lignes de code. Je veux créer plus de méthodes qui font exactement la même chose, à l'exception d'un petit calcul qui va changer une ligne de code. C'est une application parfaite pour passer un pointeur de fonction pour remplacer cette seule ligne, mais Java n'a pas de pointeurs de fonction. Quelle est ma meilleure alternative?
java
closures
function-pointers
Bill le lézard
la source
la source
::
opératrice, en revanche ...Réponses:
Classe intérieure anonyme
Supposons que vous souhaitiez qu'une fonction soit transmise avec un
String
paramètre qui renvoie unint
.Vous devez d'abord définir une interface avec la fonction comme seul membre, si vous ne pouvez pas réutiliser une interface existante.
Une méthode qui prend le pointeur accepterait simplement une
StringFunction
instance comme ceci:Et serait appelé ainsi:
EDIT: En Java 8, vous pouvez l'appeler avec une expression lambda:
la source
Pour chaque "pointeur de fonction", je créerais une petite classe de foncteurs qui implémente votre calcul. Définissez une interface que toutes les classes implémenteront et passez des instances de ces objets dans votre plus grande fonction. Il s'agit d'une combinaison du " modèle de commande " et du " modèle de stratégie ".
L'exemple de @ sblundy est bon.
la source
Lorsqu'il existe un nombre prédéfini de calculs différents que vous pouvez effectuer sur cette ligne, l'utilisation d'une énumération est un moyen rapide mais clair d'implémenter un modèle de stratégie.
Évidemment, la déclaration de méthode de stratégie, ainsi qu'exactement une instance de chaque implémentation sont toutes définies dans une seule classe / fichier.
la source
Vous devez créer une interface qui fournit les fonctions que vous souhaitez faire circuler. par exemple:
Ensuite, lorsque vous devez passer une fonction, vous pouvez implémenter cette interface:
Enfin, la fonction de carte utilise le passé dans Function1 comme suit:
Vous pouvez souvent utiliser Runnable au lieu de votre propre interface si vous n'avez pas besoin de passer de paramètres, ou vous pouvez utiliser diverses autres techniques pour rendre le nombre de paramètres moins "fixe", mais c'est généralement un compromis avec la sécurité de type. (Ou vous pouvez remplacer le constructeur pour que votre objet fonction passe dans les paramètres de cette façon .. il existe de nombreuses approches, et certaines fonctionnent mieux dans certaines circonstances.)
la source
Références de méthode à l'aide de l'
::
opérateurVous pouvez utiliser des références de méthode dans des arguments de méthode où la méthode accepte une interface fonctionnelle . Une interface fonctionnelle est une interface qui ne contient qu'une seule méthode abstraite. (Une interface fonctionnelle peut contenir une ou plusieurs méthodes par défaut ou méthodes statiques.)
IntBinaryOperator
est une interface fonctionnelle. Sa méthode abstraite,,applyAsInt
accepte deuxint
s comme paramètres et renvoie unint
.Math.max
accepte également deuxint
s et renvoie unint
. Dans cet exemple,A.method(Math::max);
faitparameter.applyAsInt
envoyer ses deux valeurs d'entrée àMath.max
et retourner le résultat de celaMath.max
.En général, vous pouvez utiliser:
au lieu de:
ce qui est l'abréviation de:
Pour plus d'informations, voir l' opérateur :: (double colon) dans Java 8 et Java Language Specification §15.13 .
la source
Vous pouvez également le faire (ce qui, dans certaines occasions RARE, a du sens). Le problème (et c'est un gros problème) est que vous perdez toute la sécurité de type d'utilisation d'une classe / interface et que vous devez faire face au cas où la méthode n'existe pas.
Il présente l '"avantage" que vous pouvez ignorer les restrictions d'accès et appeler des méthodes privées (non illustré dans l'exemple, mais vous pouvez appeler des méthodes que le compilateur ne vous laisserait normalement pas appeler).
Encore une fois, c'est un cas rare que cela a du sens, mais dans ces occasions, c'est un bel outil à avoir.
la source
Si vous n'avez qu'une seule ligne différente, vous pouvez ajouter un paramètre tel qu'un indicateur et une instruction if (indicateur) qui appelle une ligne ou l'autre.
la source
Vous pouvez également être intéressé par les travaux en cours pour Java 7 impliquant des fermetures:
Quel est l'état actuel des fermetures en Java?
http://gafter.blogspot.com/2006/08/closures-for-java.html
http://tech.puredanger.com/java7/#closures
la source
Nouvelles interfaces fonctionnelles et références de méthode Java 8 à l'aide de l'
::
opérateur.Java 8 est capable de maintenir des références de méthode (MyClass :: new) avec des pointeurs " @ Functional Interface ". Il n'y a pas besoin du même nom de méthode, seule la même signature de méthode est requise.
Exemple:
Alors, qu'est-ce que nous avons ici?
VOUS DEVEZ UTILISER DES INTERFACES FONCTIONNELLES POUR LES AUDITEURS UNIQUEMENT ET UNIQUEMENT POUR CELA!
Parce que tous les autres pointeurs de fonction sont vraiment mauvais pour la lisibilité du code et pour la capacité de comprendre. Cependant, les références de méthode directes sont parfois utiles, avec foreach par exemple.
Il existe plusieurs interfaces fonctionnelles prédéfinies:
Pour les versions antérieures de Java, vous devriez essayer les bibliothèques de goyave, qui ont des fonctionnalités et une syntaxe similaires, comme Adrian Petrescu l'a mentionné ci-dessus.
Pour plus de recherche, regardez Java 8 Cheatsheet
et merci à The Guy with The Hat pour le lien §15.13 du Java Language Specification .
la source
La réponse de @ sblundy est excellente, mais les classes internes anonymes ont deux petits défauts, le principal étant qu'elles ont tendance à ne pas être réutilisables et le secondaire est une syntaxe volumineuse.
La bonne chose est que son modèle se développe en classes complètes sans aucun changement dans la classe principale (celle qui effectue les calculs).
Lorsque vous instanciez une nouvelle classe, vous pouvez passer des paramètres dans cette classe qui peuvent agir comme des constantes dans votre équation - donc si l'une de vos classes internes ressemble à ceci:
mais parfois vous en avez besoin:
et peut-être un tiers qui est:
plutôt que de créer deux classes internes anonymes ou d'ajouter un paramètre "passthrough", vous pouvez créer une seule classe ACTUAL que vous instanciez comme:
Il stockerait simplement la constante dans la classe et l'utiliserait dans la méthode spécifiée dans l'interface.
En fait, si CONNAISSEZ que votre fonction ne sera pas stockée / réutilisée, vous pouvez le faire:
Mais les classes immuables sont plus sûres - je ne peux pas trouver de justification pour rendre une classe comme celle-ci mutable.
Je ne poste vraiment ceci que parce que je grince des dents chaque fois que j'entends une classe interne anonyme - j'ai vu beaucoup de code redondant qui était "requis" parce que la première chose que le programmeur a fait était de devenir anonyme alors qu'il aurait dû utiliser une classe réelle et jamais repensé sa décision.
la source
Les bibliothèques Google Guava , qui deviennent très populaires, ont un objet Function et Predicate générique qu'elles ont intégré dans de nombreuses parties de leur API.
la source
Cela ressemble à un modèle de stratégie pour moi. Découvrez les modèles Java de fluffycat.com.
la source
Une des choses qui me manque vraiment lors de la programmation en Java est les rappels de fonctions. Une situation où le besoin de ces derniers se présentait continuellement était dans les hiérarchies de traitement récursif où vous souhaitez effectuer une action spécifique pour chaque élément. Comme parcourir une arborescence de répertoires ou traiter une structure de données. Le minimaliste en moi déteste devoir définir une interface, puis une implémentation pour chaque cas spécifique.
Un jour, je me suis demandé pourquoi pas? Nous avons des pointeurs de méthode - l'objet Method. Avec l'optimisation des compilateurs JIT, l'invocation réfléchie ne porte plus vraiment une énorme pénalité de performance. Et en plus de, disons, la copie d'un fichier d'un emplacement à un autre, le coût de l'invocation de la méthode réfléchie est insignifiant.
En y réfléchissant davantage, j'ai réalisé qu'un rappel dans le paradigme de POO nécessite de lier un objet et une méthode ensemble - entrez l'objet de rappel.
Découvrez ma solution basée sur la réflexion pour les rappels en Java . Gratuit pour toute utilisation.
la source
OK, ce fil est déjà assez vieux, donc très probablement ma réponse n'est pas utile pour la question. Mais puisque ce fil m'a aidé à trouver ma solution, je vais le mettre ici de toute façon.
J'avais besoin d'utiliser une méthode statique variable avec une entrée et une sortie connues (toutes deux doubles ). Alors, connaissant le package et le nom de la méthode, je pourrais travailler comme suit:
pour une fonction qui accepte un double comme paramètre.
Donc, dans ma situation concrète, je l'ai initialisé avec
et l'a invoqué plus tard dans une situation plus complexe avec
où l'activité est une valeur double arbitraire. Je pense peut-être à faire cela un peu plus abstrait et à le généraliser, comme l'a fait SoftwareMonkey, mais actuellement je suis assez content de la façon dont c'est. Trois lignes de code, pas de classes et d'interfaces nécessaires, c'est pas trop mal.
la source
code
démarque, j'étais trop impatient et stupide pour le trouver ;-)Pour faire la même chose sans interfaces pour un tableau de fonctions:
la source
Découvrez Lambdaj
http://code.google.com/p/lambdaj/
et en particulier sa nouvelle fonction de fermeture
http://code.google.com/p/lambdaj/wiki/Closures
et vous trouverez un moyen très lisible de définir une fermeture ou un pointeur de fonction sans créer d'interface vide de sens ou utiliser des classes internes laides
la source
Wow, pourquoi ne pas simplement créer une classe Delegate qui n'est pas si difficile étant donné que je l'ai déjà fait pour java et l'utiliser pour passer en paramètre où T est le type de retour. Je suis désolé mais en tant que programmeur C ++ / C # en général, je viens d'apprendre Java, j'ai besoin de pointeurs de fonction car ils sont très pratiques. Si vous connaissez une classe qui traite des informations de méthode, vous pouvez le faire. Dans les bibliothèques java, ce serait java.lang.reflect.method.
Si vous utilisez toujours une interface, vous devez toujours l'implémenter. Dans la gestion des événements, il n'y a vraiment pas de meilleur moyen d'enregistrer / de désinscrire de la liste des gestionnaires, mais pour les délégués où vous devez passer des fonctions et non le type de valeur, ce qui fait qu'une classe déléguée le gère pour surclasse une interface.
la source
Aucune des réponses de Java 8 n'a donné un exemple complet et cohérent, alors voici.
Déclarez la méthode qui accepte le "pointeur de fonction" comme suit:
Appelez-la en fournissant à la fonction une expression lambda:
la source
Si quelqu'un a du mal à passer une fonction qui prend un ensemble de paramètres pour définir son comportement mais un autre ensemble de paramètres sur lesquels exécuter, comme Scheme:
voir Fonction Pass avec comportement défini en paramètre en Java
la source
Depuis Java8, vous pouvez utiliser lambdas, qui possède également des bibliothèques dans l'API SE 8 officielle.
Utilisation: Vous devez utiliser une interface avec une seule méthode abstraite. Faites-en une instance (vous voudrez peut-être utiliser celui java SE 8 déjà fourni) comme ceci:
Pour plus d'informations, consultez la documentation: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
la source
Avant Java 8, le substitut le plus proche des fonctionnalités de type pointeur de fonction était une classe anonyme. Par exemple:
Mais maintenant, dans Java 8, nous avons une alternative très soignée connue sous le nom d' expression lambda , qui peut être utilisée comme:
où isBiggerThan est une méthode dans
CustomClass
. Nous pouvons également utiliser des références de méthode ici:la source