Récemment, j'ai beaucoup lu sur la prochaine version de Java, qui pourrait prendre en charge les fermetures . Je sens que je comprends assez bien ce que sont les fermetures, mais je ne peux pas penser à un exemple concret de la façon dont elles rendraient un langage "orienté objet" mieux. Quelqu'un peut-il me donner un cas d'utilisation spécifique dans lequel une fermeture serait nécessaire (ou même préférable)?
Réponses
Trop de publicités?En tant que programmeur Lisp je souhaiterais que la communauté Java comprend la différence suivante: les fonctions comme des objets contre les fermetures.
a) les fonctions peuvent être nommés ou anonymes. Mais ils peuvent aussi être des objets d'eux-mêmes. Cela permet des fonctions à être passés comme arguments, retourné à partir de fonctions ou stockés dans des structures de données. Cela signifie que les fonctions sont des objets de première classe dans un langage de programmation.
Les fonctions anonymes ne pas ajouter beaucoup à la langue, ils vous permettent d'écrire des fonctions en moins.
b) Une fermeture est une fonction en plus d'un environnement contraignant. les fermetures peuvent être transmises vers le bas (comme paramètres) ou retournés vers le haut (comme valeurs de retour). Cela permet à la fonction de référence à des variables de son environnement, même si le code environnant n'est plus actif.
Si vous en avez un) dans une langue, alors la question se pose quoi faire à propos de b)? Il y a des langues qui ont un), mais pas b). Dans le monde de la programmation fonctionnelle (fonctions) et b (qui sert de fermeture) est aujourd'hui la norme. Smalltalk avait un) (les blocs sont des fonctions anonymes) pour une longue période, mais ensuite certains dialectes de Smalltalk ajout du support pour b) (blocs que les fermetures).
Vous pouvez imaginer que vous obtenez un peu différente du modèle de programmation si vous ajoutez des fonctions et de la fermeture de la langue.
À partir d'un point de vue pragmatique, la fonction anonyme ajoute quelques courtes notation où vous passez ou d'appeler des fonctions. Ce peut être une bonne chose.
La fermeture (fonction plus contraignant) permet par exemple de créer une fonction qui a accès à certaines variables (par exemple, pour une valeur de compteur). Maintenant, vous pouvez stocker cette fonction dans un objet, l'accès et l'invoquer. Le contexte de la fonction de l'objet est maintenant non seulement les objets qu'il a accès, mais aussi les variables qu'il a accès via des liaisons. C'est aussi utile, mais vous pouvez voir que la variable de liaisons ou accès à des variables d'objet est maintenant une question: quand doit-être quelque chose d'un lexicale variable (qui peut être consulté par une fermeture) et quand doit-il être une variable d'un certain objet (un slot
). Lorsque que quelque chose devrait être d'une fermeture ou d'un objet? Vous pouvez utiliser à la fois dans la façon semblable. Une habitude exercice de programmation pour les étudiants d'apprentissage (un dialecte de Lisp) est d'écrire un objet simple système à l'aide de fermetures.
Le résultat est plus compliqué langage de programmation et un plus compliqué modèle d'exécution. Trop compliqué?
Elles ne font pas un langage Orienté Objet de mieux. Ils sont, en pratique, les langues plus pratique.
Si vous attaquez un problème avec le OO marteau - représentent tout ce que les interactions entre les objets, puis d'une fermeture n'a pas de sens. Dans une classe à base de langage OO, fermetures sont la rempli de fumée arrière-salles où des choses se fait, mais personne n'en parle après. Sur le plan conceptuel, c'est une horreur.
Dans la pratique, il est extrêmement pratique. Je ne veux pas vraiment à définir un nouveau type d'objet à tenir contexte, l'établissement du "faire des trucs" pour elle la méthode, l'instancier, et de remplir le contexte... je veux juste dire au compilateur, "regarder, voir ce que j'ai accès à maintenant? C'est le contexte qui je veux, et voici le code que je veux l'utiliser pour tenir à cela pour moi, jusqu'à ce que j'en ai besoin".
Fantastique choses.
La chose la plus évidente serait un pseudo-remplacement pour toutes les classes qui ont juste une seule méthode appelée run () ou actionPerformed () ou quelque chose comme ça. Ainsi, au lieu de créer un thread avec un Runnable incorporé, vous utiliseriez plutôt une fermeture. Pas plus puissant que ce que nous avons maintenant, mais beaucoup plus pratique et concis.
Alors avons-nous besoin de fermetures? Est-ce qu'ils seraient bien d'avoir? Bien sûr, tant qu'ils ne se sentent pas bloqués, comme je le crains.
Je suppose que pour supporter les concepts de base de la programmation fonctionnelle, vous avez besoin de fermetures. Rend le code plus élégant et composable avec le support des fermetures . J'aime aussi l'idée de passer des lignes de code en tant que paramètres de fonctions.
Il y a quelques très utile "des fonctions d'ordre supérieur", qui peuvent effectuer des opérations sur des listes à l'aide de fermetures. Des fonctions d'ordre supérieur sont des fonctions ayant la fonction des objets comme paramètres.
E. g. c'est une opération très courante pour appliquer une transformation à chaque élément d'une liste. Cet ordre supérieur de la fonction est communément appelé "carte" ou "collect". (Voir l' *. la propagation de l'opérateur de Groovy).
Par exemple à la place de chaque élément dans une liste sans fermetures vous serait probablement écrire:
List<Integer> squareInts(List<Integer> is){
List<Integer> result = new ArrayList<Integer>(is.size());
for (Integer i:is)
result.add(i*i);
return result;
}
À l'aide de fermetures et de la carte et le projet de syntaxe, vous pouvez l'écrire comme ça:
is.map({Integer i => i*i})
(Il y a un possible problème de performance en ce qui concerne la boxe de types primitifs.)
Comme l'a expliqué Pop Catalin il y a un autre ordre supérieur de la fonction appelée "sélectionner" ou "filtre": Il peut être utilisé pour obtenir tous les éléments dans une liste se conformer à certaines conditions. Par exemple:
Au lieu de:
void onlyStringsWithMoreThan4Chars(List<String> strings){
List<String> result = new ArrayList<String>(str.size()); // should be enough
for (String str:strings)
if (str.length() > 4) result.add(str);
return result;
}
Au lieu de cela, vous pourriez écrire quelque chose comme
strings.select({String str => str.length() > 4});
à l'aide de la proposition.
Vous pouvez regarder le Groovy de la syntaxe, qui est une extension du langage Java pour soutenir les fermetures de la droite maintenant. Voir le chapitre sur les collections de l' Groovy Guide de l'Utilisateur pour plus d'exemples de quoi faire avec les fermetures.
Une remarque:
Il y a peut-être quelques précisions nécessaires concernant le terme 'fermeture'. Ce que j'ai indiqués ci-dessus sont strictement parlé pas de fermetures. Ils sont juste " en fonction des objets. Une fermeture est tout ce qui peut capturer ou de "fermer" - (lexicale) contexte du code qui l'entourent. En ce sens, il y a des fermetures en Java droit maintenant, c'est à dire anonyme classes:
Runnable createStringPrintingRunnable(final String str){
return new Runnable(){
public void run(){
System.out.println(str); // this accesses a variable from an outer scope
}
};
}