Groovy - Fermetures

Une fermeture est un court bloc de code anonyme. Il s'étend normalement sur quelques lignes de code. Une méthode peut même prendre le bloc de code comme paramètre. Ils sont de nature anonyme.

Voici un exemple de fermeture simple et à quoi cela ressemble.

class Example {
   static void main(String[] args) {
      def clos = {println "Hello World"};
      clos.call();
   } 
}

Dans l'exemple ci-dessus, la ligne de code - {println "Hello World"} est appelée fermeture. Le bloc de code référencé par cet identifiant peut être exécuté avec l'instruction call.

Lorsque nous exécutons le programme ci-dessus, nous obtiendrons le résultat suivant -

Hello World

Paramètres formels dans les fermetures

Les fermetures peuvent également contenir des paramètres formels pour les rendre plus utiles, tout comme les méthodes de Groovy.

class Example {
   static void main(String[] args) {
      def clos = {param->println "Hello ${param}"};
      clos.call("World");
   } 
}

Dans l'exemple de code ci-dessus, notez l'utilisation de $ {param} qui oblige la fermeture à prendre un paramètre. Lors de l'appel de la fermeture via l'instruction clos.call, nous avons maintenant la possibilité de passer un paramètre à la fermeture.

Lorsque nous exécutons le programme ci-dessus, nous obtiendrons le résultat suivant -

Hello World

L'illustration suivante répète l'exemple précédent et produit le même résultat, mais montre qu'un paramètre unique implicite désigné comme il peut être utilisé. Ici, «c'est» est un mot-clé dans Groovy.

class Example {
   static void main(String[] args) {
      def clos = {println "Hello ${it}"};
      clos.call("World");
   } 
}

Lorsque nous exécutons le programme ci-dessus, nous obtiendrons le résultat suivant -

Hello World

Fermetures et variables

Plus formellement, les fermetures peuvent faire référence à des variables au moment où la fermeture est définie. Voici un exemple de la manière dont cela peut être réalisé.

class Example {     
   static void main(String[] args) {
      def str1 = "Hello";
      def clos = {param -> println "${str1} ${param}"}
      clos.call("World");
		
      // We are now changing the value of the String str1 which is referenced in the closure
      str1 = "Welcome";
      clos.call("World");
   } 
}

Dans l'exemple ci-dessus, en plus de passer un paramètre à la fermeture, nous définissons également une variable appelée str1. La fermeture prend également la variable avec le paramètre.

Lorsque nous exécutons le programme ci-dessus, nous obtiendrons le résultat suivant -

Hello World 
Welcome World

Utilisation des fermetures dans les méthodes

Les fermetures peuvent également être utilisées comme paramètres de méthodes. Dans Groovy, de nombreuses méthodes intégrées pour les types de données tels que les listes et les collections ont des fermetures comme type de paramètre.

L'exemple suivant montre comment une fermeture peut être envoyée à une méthode en tant que paramètre.

class Example { 
   def static Display(clo) {
      // This time the $param parameter gets replaced by the string "Inner"         
      clo.call("Inner");
   } 
	
   static void main(String[] args) {
      def str1 = "Hello";
      def clos = { param -> println "${str1} ${param}" }
      clos.call("World");
		
      // We are now changing the value of the String str1 which is referenced in the closure
      str1 = "Welcome";
      clos.call("World");
		
      // Passing our closure to a method
      Example.Display(clos);
   } 
}

Dans l'exemple ci-dessus,

  • Nous définissons une méthode statique appelée Display qui prend une fermeture comme argument.

  • Nous définissons ensuite une fermeture dans notre méthode principale et la passons à notre méthode Display en tant que paramètre.

Lorsque nous exécutons le programme ci-dessus, nous obtiendrons le résultat suivant -

Hello World 
Welcome World 
Welcome Inner

Fermetures dans les collections et la chaîne

Plusieurs méthodes List, Map et String acceptent une fermeture comme argument. Regardons un exemple de la façon dont les fermetures peuvent être utilisées dans ces types de données.

Utilisation de fermetures avec des listes

L'exemple suivant montre comment les fermetures peuvent être utilisées avec les listes. Dans l'exemple suivant, nous définissons d'abord une simple liste de valeurs. Le type de collection de liste définit ensuite une fonction appelée.each. Cette fonction prend une fermeture comme paramètre et applique la fermeture à chaque élément de la liste.

class Example {
   static void main(String[] args) {
      def lst = [11, 12, 13, 14];
      lst.each {println it}
   } 
}

Lorsque nous exécutons le programme ci-dessus, nous obtiendrons le résultat suivant -

11 
12 
13 
14

Utilisation des fermetures avec des cartes

L'exemple suivant montre comment les fermetures peuvent être utilisées avec Maps. Dans l'exemple suivant, nous définissons d'abord une simple carte d'éléments de valeur clé. Le type de collection de cartes définit ensuite une fonction appelée .each. Cette fonction prend une fermeture comme paramètre et applique la fermeture à chaque paire clé-valeur de la carte.

class Example {
   static void main(String[] args) {
      def mp = ["TopicName" : "Maps", "TopicDescription" : "Methods in Maps"]             
      mp.each {println it}
      mp.each {println "${it.key} maps to: ${it.value}"}
   } 
}

Lorsque nous exécutons le programme ci-dessus, nous obtiendrons le résultat suivant -

TopicName = Maps 
TopicDescription = Methods in Maps 
TopicName maps to: Maps 
TopicDescription maps to: Methods in Maps

Souvent, nous souhaitons effectuer une itération sur les membres d'une collection et appliquer une logique uniquement lorsque l'élément répond à un critère. Ceci est facilement traité avec une instruction conditionnelle dans la fermeture.

class Example {
   static void main(String[] args) {
      def lst = [1,2,3,4];
      lst.each {println it}
      println("The list will only display those numbers which are divisible by 2")
      lst.each{num -> if(num % 2 == 0) println num}
   } 
}

L'exemple ci-dessus montre l'expression conditionnelle if (num% 2 == 0) utilisée dans la fermeture qui est utilisée pour vérifier si chaque élément de la liste est divisible par 2.

Lorsque nous exécutons le programme ci-dessus, nous obtiendrons le résultat suivant -

1 
2 
3 
4 
The list will only display those numbers which are divisible by 2.
2 
4

Méthodes utilisées avec les fermetures

Les fermetures elles-mêmes fournissent certaines méthodes.

N ° Sr. Méthodes et description
1 trouver()

La méthode find trouve la première valeur d'une collection qui correspond à un critère.

2 Trouver tout()

Il trouve toutes les valeurs de l'objet récepteur correspondant à la condition de fermeture.

3 any () & every ()

La méthode any parcourt chaque élément d'une collection pour vérifier si un prédicat booléen est valide pour au moins un élément.

4 collecte()

La méthode collect itère dans une collection, convertissant chaque élément en une nouvelle valeur en utilisant la fermeture comme transformateur.