Chapitre Les bases du language Groovy La gestion des Closures {{ resumeCollapse ? '-' : '+' }} Résumé Cette leçon présente les closures, la syntaxe et leur utilité Dernière modification : Dec 08 , 2024 {{ !slideMode ? "Passer en mode diapositive" : "Passer en mode lecture" }} La gestion des Closures Created by Sylvain Leroy ## Les clôtures ( closures ) ### Une fonctionnalité importante apparue avant Java 8 et les lambdas ### Les clôtures sont un morceau de code enveloppé dans un objet. ### Avant les closures et les lambdas, nous utilisions des classes anonymes et des Marker interfaces ```language-java interface Msg { public void show(); } class AnonymousClass { public void run() { // classe anonyme héritant la classe Msg Msg msg = new Msg() { public void show() { System.out.println("Welcome To WayToLearnX!"); } }; msg.show(); } } ``` ### Syntaxe ```language-groovy { expression } { it -> println it } // Closure avec un paramètre { println it } // L'argument par défaut est it { name -> println name } // L'argument par défaut est it { int x, inty -> x+y } // Une closure peut prendre plusieurs arguments ``` ### Comment appeler une closure ```language-groovy def closure1 = { 10 } // Crée une closure qui retourne "10" println(closure1.call()) // Affichage "10" assert closure1() == 10 // Est vrai def b = closure instanceof Closure println(b) // Affiche true def closure2 = { print 10 } // Crée une closure qui affiche "10" closure2.call() // Affiche "10" def closure3 = { println it } // Créer une closure qui affiche le paramètre passé closure3.call(5) // Affichera "5" closure3.call() ; // Affichera "null" { it -> println it }.call(5) // Affichera "5" ``` ## Avantage des closures * Les clôtures sont beaucoup moins verbeuses * Les clôtures sont proches des pointeurs de fonctions * *limite la prolifération d'interfaces* : Runnable, Function, Comparator, Predicate... * les clotûres ont accès aux variables locales ( portée englobante) ## Exemple de closures ```language-groovy { item++ } { -> item++ } { println it } { it -> println it } { name -> println name } { String x, int y -> println "hey ${x} the value is ${y}" } ``` ## Memoisation Mise en cache des résultats d'une closure ```language-groovy // SLOW def fib fib = { long n -> n<2 ? n : fib(n-1)+fib(n-2) } assert fib(15) == 610 // slow! //FAST fib = { long n -> n< 2 ? n : fib(n-1)+fib(n-2) }.memoize() assert fib(25) == 75025 // fast! ``` ## Composition de closures Permet de combiner en programmation fonctionnelle des closures avec l'opérateur **<<** ```language-groovy def plus2 = { it + 2 } def times3 = { it * 3 } def times3plus2 = plus2 << times3 assert times3plus2(3) == 11 assert times3plus2(4) == plus2(times3(4)) def plus2times3 = times3 << plus2 assert plus2times3(3) == 15 assert plus2times3(5) == times3(plus2(5)) // reverse composition assert times3plus2(3) == (times3 >> plus2)(3) ``` ## Composition de closures Supposons que nous ayons deux Closures simples, l'une pour doubler un nombre et l'autre pour ajouter 10 : ```language-groovy def doubler = { nombre -> nombre * 2 } def ajouterDix = { nombre -> nombre + 10 } ``` ## Composition de closures Maintenant, nous pouvons composer ces deux Closures pour créer une nouvelle Closure qui double un nombre puis ajoute 10 : ```language-groovy def composition = doubler << ajouterDix ``` ## Composition de closures Dans cet exemple, << est l'opérateur de composition de Closure. La nouvelle Closure composition prendra un nombre, le doublera à l'aide de la première Closure (doubler), puis ajoutera 10 à l'aide de la deuxième Closure (ajouterDix). Utilisons cette composition sur un nombre spécifique : ## Composition de closures ```groovy def resultat = composition(5) println resultat // Affiche 20 (5 * 2 + 10) ``` ## Pointeurs de méthodes #1 Permet de combiner en programmation fonctionnelle des closures. ```language-groovy def str = 'example of method reference' def fun = str.&toUpperCase def upper = fun() assert upper == str.toUpperCase() ``` ## Pointeurs de méthodes #2 Permet d'utiliser les pointeurs de méthodes en Groovy 3.0 ```language-groovy import groovy.transform.CompileStatic import static java.util.stream.Collectors.toList @CompileStatic void methodRefs() { assert 6G == [1G, 2G, 3G].stream().reduce(0G, BigInteger::add) assert [4G, 5G, 6G] == [1G, 2G, 3G].stream().map(3G::add).collect(toList()) assert [1G, 2G, 3G] == [1L, 2L, 3L].stream().map(BigInteger::valueOf).collect(toList()) assert [1G, 2G, 3G] == [1L, 2L, 3L].stream().map(3G::valueOf).collect(toList()) } methodRefs() ``` ## Les closures et Gradle * Utilisées pour manipuler les collections * Utilisées pour les maps * Utilisées comme lambda pour certains appels de méthodes gradle ## Gradle et les closures ```language-gradle // Iterable gets an each() method configurations.runtimeClasspath.each { File f -> println f } file.eachLine { line, lineNo -> println ("Line $ {lineNo} line $ line") } dependencies { compile group: 'commons-collections', name: 'commons-collections', version: '3.2' testCompile group: 'junit', name: 'junit', version: '4.+' } ``` # Fin de la leçon La gestion des Closures Created by Sylvain Leroy ## Les clôtures ( closures ) ### Une fonctionnalité importante apparue avant Java 8 et les lambdas ### Les clôtures sont un morceau de code enveloppé dans un objet. ### Avant les closures et les lambdas, nous utilisions des classes anonymes et des Marker interfaces ```language-java interface Msg { public void show(); } class AnonymousClass { public void run() { // classe anonyme héritant la classe Msg Msg msg = new Msg() { public void show() { System.out.println("Welcome To WayToLearnX!"); } }; msg.show(); } } ``` ### Syntaxe ```language-groovy { expression } { it -> println it } // Closure avec un paramètre { println it } // L'argument par défaut est it { name -> println name } // L'argument par défaut est it { int x, inty -> x+y } // Une closure peut prendre plusieurs arguments ``` ### Comment appeler une closure ```language-groovy def closure1 = { 10 } // Crée une closure qui retourne "10" println(closure1.call()) // Affichage "10" assert closure1() == 10 // Est vrai def b = closure instanceof Closure println(b) // Affiche true def closure2 = { print 10 } // Crée une closure qui affiche "10" closure2.call() // Affiche "10" def closure3 = { println it } // Créer une closure qui affiche le paramètre passé closure3.call(5) // Affichera "5" closure3.call() ; // Affichera "null" { it -> println it }.call(5) // Affichera "5" ``` ## Avantage des closures * Les clôtures sont beaucoup moins verbeuses * Les clôtures sont proches des pointeurs de fonctions * *limite la prolifération d'interfaces* : Runnable, Function, Comparator, Predicate... * les clotûres ont accès aux variables locales ( portée englobante) ## Exemple de closures ```language-groovy { item++ } { -> item++ } { println it } { it -> println it } { name -> println name } { String x, int y -> println "hey ${x} the value is ${y}" } ``` ## Memoisation Mise en cache des résultats d'une closure ```language-groovy // SLOW def fib fib = { long n -> n<2 ? n : fib(n-1)+fib(n-2) } assert fib(15) == 610 // slow! //FAST fib = { long n -> n< 2 ? n : fib(n-1)+fib(n-2) }.memoize() assert fib(25) == 75025 // fast! ``` ## Composition de closures Permet de combiner en programmation fonctionnelle des closures avec l'opérateur **<<** ```language-groovy def plus2 = { it + 2 } def times3 = { it * 3 } def times3plus2 = plus2 << times3 assert times3plus2(3) == 11 assert times3plus2(4) == plus2(times3(4)) def plus2times3 = times3 << plus2 assert plus2times3(3) == 15 assert plus2times3(5) == times3(plus2(5)) // reverse composition assert times3plus2(3) == (times3 >> plus2)(3) ``` ## Composition de closures Supposons que nous ayons deux Closures simples, l'une pour doubler un nombre et l'autre pour ajouter 10 : ```language-groovy def doubler = { nombre -> nombre * 2 } def ajouterDix = { nombre -> nombre + 10 } ``` ## Composition de closures Maintenant, nous pouvons composer ces deux Closures pour créer une nouvelle Closure qui double un nombre puis ajoute 10 : ```language-groovy def composition = doubler << ajouterDix ``` ## Composition de closures Dans cet exemple, << est l'opérateur de composition de Closure. La nouvelle Closure composition prendra un nombre, le doublera à l'aide de la première Closure (doubler), puis ajoutera 10 à l'aide de la deuxième Closure (ajouterDix). Utilisons cette composition sur un nombre spécifique : ## Composition de closures ```groovy def resultat = composition(5) println resultat // Affiche 20 (5 * 2 + 10) ``` ## Pointeurs de méthodes #1 Permet de combiner en programmation fonctionnelle des closures. ```language-groovy def str = 'example of method reference' def fun = str.&toUpperCase def upper = fun() assert upper == str.toUpperCase() ``` ## Pointeurs de méthodes #2 Permet d'utiliser les pointeurs de méthodes en Groovy 3.0 ```language-groovy import groovy.transform.CompileStatic import static java.util.stream.Collectors.toList @CompileStatic void methodRefs() { assert 6G == [1G, 2G, 3G].stream().reduce(0G, BigInteger::add) assert [4G, 5G, 6G] == [1G, 2G, 3G].stream().map(3G::add).collect(toList()) assert [1G, 2G, 3G] == [1L, 2L, 3L].stream().map(BigInteger::valueOf).collect(toList()) assert [1G, 2G, 3G] == [1L, 2L, 3L].stream().map(3G::valueOf).collect(toList()) } methodRefs() ``` ## Les closures et Gradle * Utilisées pour manipuler les collections * Utilisées pour les maps * Utilisées comme lambda pour certains appels de méthodes gradle ## Gradle et les closures ```language-gradle // Iterable gets an each() method configurations.runtimeClasspath.each { File f -> println f } file.eachLine { line, lineNo -> println ("Line $ {lineNo} line $ line") } dependencies { compile group: 'commons-collections', name: 'commons-collections', version: '3.2' testCompile group: 'junit', name: 'junit', version: '4.+' } ``` # Fin de la leçon Slideshow Aperçu Leçon précédente Prochaine leçon Please enable JavaScript to view the comments powered by Disqus.