Voici le chapitre 11 sur les expressions lambda et les références de méthodes en Java.
Si vous avez des remarques ou suggestions afin de le parfaire.
N’hésitez pas à me contacter via mon email:
pr.azizdarouichi@gmail.com.
Bonne lecture.
2. 2
Expressions Lambda
Références de méthodes
Le package java.util.function
Interface Function
Interface Predicate
Interface Consumer
Interface Supplier
Interface BinaryOperator
Q & A
Références
Expressions Lambda
Références de méthodes
Le package java.util.function
Interface Function
Interface Predicate
Interface Consumer
Interface Supplier
Interface BinaryOperator
Q & A
Références
Chapitre 11: Expression Lambda et références de méthodes
3. 3
Expressions Lambda
Une expression Lambda constitue une notation abrégée d’une
méthode fonctionnelle d’une interface fonctionnelle.
Une expression Lambda peut ou non renvoyer une valeur.
Les expressions Lambda permettent d'écrire du code plus concis.
4. 4
Expressions Lambda
Une expression Lambda est une fonction anonyme : sa définition
se fait sans déclaration explicite du type de retour, ni de
modificateurs d'accès ni de nom.
Lorsque l'expression lambda est évaluée par le compilateur, celui-ci
infère le type vers l'interface fonctionnelle.
Cela lui permet d'obtenir des informations sur les paramètres
utilisés, le type de la valeur de retour, les exceptions qui peuvent
être levées.
5. 5
Syntaxe d'une expression lambda
La syntaxe générale d’une expression Lambda est la suivante:
(listeDesParamètres) -> corps;
L'opérateur -> sépare le ou les paramètres du bloc de code qui
va les utiliser.
listeDesParamètres: liste d’arguments avec un éventuel type,
entre parenthèses; si un seul argument est présent (sans type),
on peut omettre les parenthèses.
corps: le corps de la méthode:
soit une seule expression; sa valeur, si elle existe, est renvoyée.
soit un bloc d’instructions pouvant contenir une ou plusieurs
instructions return.
il faut toujours terminer une expression Lambda par un ';'
6. 6
Expressions Lambda
Remarque:
Le type du paramètre n'est pas obligatoire : le compilateur va
tenter de réaliser une inférence du type pour le déterminer selon le
contexte.
7. 7
Les paramètres d'une expression lambda
Les paramètres de l'expression lambda doivent donc être déclarés
à gauche de l'opérateur ->.
Les paramètres d'une expression Lambda doivent correspondre à
ceux définis dans l'interface fonctionnelle.
8. 8
Les paramètres de l'expression lambda doivent respecter certaines
règles :
une expression lambda peut n'avoir aucun, un seul ou plusieurs
paramètres.
le type des paramètres peuvent être explicitement déclaré ou être
inféré par le compilateur selon le contexte dans lequel l'expression est
utilisée.
les paramètres sont entourés de parenthèses, chacun étant séparé par
une virgule.
des parenthèses vides indiquent qu'il n'y a pas de paramètre.
s'il n'y a qu'un seul paramètre dont le type n'est pas explicitement
précisé, alors l'utilisation des parenthèses n'est pas obligatoire.
Une expression lambda peut ne pas avoir de paramètres.
Les paramètres d'une expression lambda
9. 9
Le corps d'une expression lambda
Le corps d'une expression lambda est défini à droite de l'opérateur
->.
Il peut être :
une expression unique.
un bloc de code composé d'une ou plusieurs instructions entourées
par des accolades
10. 10
Le corps de l'expression Lambda doit respecter certaines règles:
il peut n'avoir aucune, une seule ou plusieurs instructions.
lorsqu'il ne contient qu'une seule instruction, les accolades ne sont pas
obligatoires et la valeur de retour est celle de l'instruction si elle en possède
une.
lorsqu'il y a plusieurs instructions, elles doivent obligatoirement être
entourées d'accolades.
la valeur de retour est celle de la dernière expression ou void si rien n'est
retourné.
Le corps d'une expression lambda
11. 11
Expressions Lambda
Exemples:
Expressions Lambda Description
() -> { System.out.println("Salam tout le monde"); }; Afficher "Salam tout le monde" sur la sortie standard
() -> 12;
() -> { return 12 };
N'accepter aucun paramètre et renvoyer la valeur 12
x -> x * 2; Accepter un nombre et renvoyer son double
(x, y) -> x * y;
(int x, int y) -> x * y;
Accepter deux nombres et renvoyer leur produit
(String s) -> System.out.print(s);
(s)-> System.out.print(s);
s-> System.out.print(s);
Accepter une chaîne de caractères et l'afficher sur la
sortie standard sans rien renvoyer
(Point p, float x)->
{System.out.println("Valeur="+x); p.afficher();};
Accepter deux paramètres et les afficher sur la sortie
standard sans rien renvoyer
(val1, val2) -> { return val1 >= val2; };
(val1, val2) -> val1 >= val2;
Renvoyer un booléen qui précise si la première valeur
est supérieure ou égale à la seconde
14. 14
Expressions Lambda
Exemple 3:
L’interface fonctionnelle ActionListener, qui permet de réagir au
clic sur un bouton Swing.
Elle définit une méthode actionPerformed(ActionEvent event).
15. 15
Expressions Lambda
Exemple 1/3:
monBouton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
System.out.println("clic");
}
}
);
En utilisant l’expression Lambda:
monBouton.addActionListener(event->System.out.println("clic"));
16. 16
Expressions Lambda
Exemple 2/3: classe anonyme
public class WithoutLambda {
public static void main(String[] args) {
JFrame frakme=new JFrame("ActionListener Before Java 8");
JButton b=new JButton("Click Here");
b.setBounds(50,100,80,50);
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
System.out.println("Hello World!");
}
});
frame.add(b); frame.setSize(200,200);
frame.setLayout(null);
frame.setVisible(true);
}
}
17. 17
Expressions Lambda
Exemple 3/3:
public class WithLambda {
public static void main(String[] args) {
JFrame frame=new JFrame("ActionListener Java 8");
Button b=new Button("Click Here");
b.setBounds(50,100,80,50);
b.addActionListener(e -> System.out.println("Hello World!"));
frame.add(b);
frame.setSize(200,200);
frame.setLayout(null);
frame.setVisible(true);
}
}
18. 18
Expressions Lambda
La portée des variables
Une expression lambda comme une méthode d’une classe
anonyme peux accéder aux variables finales (ou effectivement
finales) de la classe dans laquelle elle est définie.
Une expression lambda se comporte syntaxiquement comme un
bloc de code imbriqué.
Une expression lambda peut avoir accès aux variables définies
dans son contexte englobant.
19. 19
La portée des variables
Dans le corps d'une expression lambda, il est donc possible
d'utiliser :
les variables passées en paramètre de l'expression
les variables définies dans le corps de l'expression
les variables final définies dans le contexte englobant
les variables effectivement final définies dans le contexte
englobant : ces variables ne sont pas déclarées final mais une
valeur leur est assignée et celle-ci n'est jamais modifiée. Il serait
donc possible de les déclarer final sans que cela n'engendre de
problème de compilation.
le concept de variables effectivement final a été introduit
depuis Java 8.
20. 20
L'utilisation d'une expression lambda
Une expression lambda ne peut être utilisée que dans un contexte
où le compilateur peut identifier l'utilisation de son type cible
(target type) qui doit être une interface fonctionnelle :
déclaration d'une variable
affectation d'une variable
valeur de retour avec l'instruction return
initialisation d'un tableau
paramètre d'une méthode ou d'un constructeur
corps d'une expression lambda
opérateur ternaire ?:
cast
21. 21
Method References (Références de méthodes)
Les références de méthodes permettent d'offrir une syntaxe
simplifiée pour invoquer une méthode comme une expression
lambda : elles offrent un raccourci syntaxique pour créer une
expression lambda dont le but est d'invoquer une méthode ou un
constructeur.
Une expression lambda correspond à une méthode anonyme
dont le type est défini par une interface fonctionnelle.
Les références de méthodes ont un rôle similaire mais au lieu de
fournir une implémentation, une référence de méthode permet
d'invoquer une méthode statique ou non ou un constructeur.
Les références de méthodes ou de constructeurs utilisent le
nouvel opérateur ::.
22. 22
Références de méthodes
La syntaxe d'une référence de méthode est composée de trois
éléments :
un qualificateur qui précise le nom d'une classe ou d'une instance sur lequel
la méthode sera invoquée
l'opérateur ::
un identifiant qui précise le nom de la méthode ou l'opérateur new pour
désigner un constructeur
23. 23
Le qualificateur peut être :
un type pour les méthodes statiques et les constructeurs
un type ou une expression pour les méthodes non statiques.
L'expression doit préciser l'objet sur lequel la méthode est
invoquée
Références de méthodes
24. 24
Une référence de constructeur comprend :
un qualificateur qui est un type dont il est possible de créer une
instance : cela exclut les interfaces et les classes abstraites
l'opérateur ::
le mot clé new
Références de méthodes
25. 25
Il existe quatre types de références de méthodes :
Type Syntaxe Exemple
Référence à une méthode statique nomClasse::nomMethodeStatique String::valueOf
Référence à une méthode sur une instance objet::nomMethode personne::toString
Référence à une méthode d'un objet
arbitraire d'un type donné
nomClasse::nomMethode Object::toString
Référence à un constructeur nomClasse::new Personne::new
Références de méthodes
26. 26
Method References et Expression Lambda
Le tableau ci-dessous donne quelques exemples de références de
méthodes et leurs expressions lambda équivalentes :
Type Référence de méthode Expression lambda
Référence à une méthode statique
System.out::println
Math::pow
x -> System.out.println(x)
(x, y) -> Math.pow(x, y)
Référence à une méthode sur une
instance
monObjet::maMethode x -> monObjet.maMethode(x)
Référence à une méthode d'un objet
arbitraire d'un type donné
String::compareToIgnoreCase
(x, y) ->
x.compareToIgnoreCase(y)
Référence à un constructeur nomClasse::new () -> new nomClasse();
29. 29
Interface Function
L'interface Function (java.util.function.Function) est l'une des
interfaces fonctionnelles les plus centrales de Java.
L'interface Function représente une méthode qui prend un
paramètre unique et renvoie une valeur unique.
java.util.function.Function<T,R>:
Sa méthode fonctionnelle a la signature R apply(T t).
Cette méthode applique la fonction donnée à son seul argument.
Elle permet donc de traiter un paramètre T et de renvoyer un type R.
Cette interface contient d’autres méthodes avec des implémentations
par défaut: andThen(), compose(), identity().
Le package java.util.function
30. 30
Exemple 1:
Voici le code pour illustrer la méthode apply():
Interface Function
import java.util.function.Function;
public class Main {
public static void main(String args[])
{
// Fonction qui prend un nombre et retourne la moitié
Function<Integer, Double> half = a -> a / 2.0;
// Appliquer la fonction pour obtenir le résultat
System.out.println(half.apply(12));
}
}
Output:
6.0
31. 31
Exemple 2:
Voici le code pour illustrer la méthode andThen():
import java.util.function.Function;
public class Main {
public static void main(String args[])
{
// Fonction qui prend un nombre et retourne la moitié
Function<Integer, Double> half = a -> a / 2.0;
// Maintenant triple l’output de la méthode half
half = half.andThen(a -> 3 * a);
// Appliquer la fonction pour obtenir le résultat
System.out.println(half.apply(10));
}
}
Output:
15.0
Interface Function
32. 32
Exemple 3:
Voici le code pour illustrer la méthode compose():
import java.util.function.Function;
public class Main {
public static void main(String args[])
{
// Fonction qui prend un nombre et retourne la moitié
Function<Integer, Double> half = a -> a / 2.0;
// Maintenant triple l’output de la méthode half
half = half.compose(a -> 3 * a);
// Appliquer la fonction pour obtenir le résultat
System.out.println(half.apply(5));
}
}
Output:
7.5
Interface Function
33. 33
Exemple 4:
Voici un code qui illustre les deux méthodes compose() et andThen():
import java.util.function.Function;
public class Main {
public static void main(String args[])
{
// Définition deux fonctions simples times2 et squared
Function<Integer, Integer> times2 = e -> e * 2;
Function<Integer, Integer> squared = e -> e * e;
// Maintenant triple l’output de la méthode half
times2.compose(squared).apply(4);
times2.andThen(squared).apply(4);
}
Output:
32
64
Interface Function
34. 34
Interface Predicate
L'interface Predicate, java.util.function.Predicate, représente une
fonction simple qui prend une valeur unique en tant que paramètre et
renvoie true ou false.
java.util.function.Predicate<T>:
Sa méthode boolean test(T t) permet de faire un test sur le paramètre et de
retourner un boolean en fonction du résultat.
L'interface Predicate contient plus de méthodes que la méthode test(),
mais les autres méthodes sont des méthodes par défaut ou statiques
que vous n'avez pas à implémenter.
Voici à quoi ressemble la définition de l'interface Predicate:
public interface Predicate {
boolean test(T t);
}
Le package java.util.function
35. 35
Exemple:
public class Test {
public static void main(String args[]) {
// créer une liste des strings
List<String> filieres = Arrays.asList("SIR","IRISI","IFA","MIASI"; "SDAD");
// déclarer le type de predicate comme string et utiliser
// expression lambda pour créer un objet
Predicate<String> p = (s)->s.endsWith("I");
// Itérer sur la liste
for (String st : filieres) {
// invoquer la méthode test()
if (p.test(st)) System.out.println(st);
}
}
}
Output:
IRISI
MIASI
Interface Predicate
36. 36
Interface Consumer
java.util.function.Consumer<T>:
Cette interface fonctionnelle est un peu particulière car c'est la seule
qui a pour vocation de modifier les données qu'elle reçoit.
Sa méthode fonctionnelle void accept(T t) est faite pour appliquer des
traitements au paramètre passer et ne retourne rien.
Le package java.util.function
37. 37
Exemple :
// Consumer pour afficher un nombre
Consumer<Integer> display = a -> System.out.println(a);
// Implémentation de display en utilisant accept()
display.accept(10);
Interface Consumer
39. 39
Interface Supplier
Exemple :
Voici le code pour illustrer la méthode get():
import java.util.function.Supplier;
public class Main{
public static void main(String args[])
{
// Cette fonction renvoie une valeur random.
Supplier<Double> randomValue = () -> Math.random();
// Afficher la valeur random en utilisant get()
System.out.println(randomValue.get());
}
}
Output:
0.5685808855697841
40. 40
Interface BinaryOperator
java.util.function.BinaryOperator<T>:
BinaryOperator représente une opération sur deux opérandes du même
type, produisant un résultat du même type.
S'utilise pour les opération de type reduce comme additionner deux
int par exemple.
Sa méthode T apply(T t, T t2) prend deux T en paramètre et renvoi
un T (T BinaryOperator(T)).
Le package java.util.function
41. 41
Interface BinaryOperator
Exemple :
Voici le code pour illustrer la méthode get():
import java.util.function.Supplier;
public class TestBinaryOperator{
public static void main(String args[])
{
BinaryOperator<Integer> sumOfSquare = (a, b) -> a * a + b * b;
Integer i = sumOfSquare.apply(3, 4);
System.out.println(i);
}
Output:
25