Vous êtes sur la page 1sur 19

Programmation fonctionnelle

Mastère de recherche M1- ENSI


F.Kboubi , ferihane.kboubi@ensi-uma.tn

Plan

Programmation fonctionnelle
Lambda expression
Interface fonctionnelle
API Stream

2 M1 - ENSI - TPA - F.KBOUBI

1
Principe programmation fonctionnelle
 Considére une fonction comme une entité de première classe (first
class citizen) sur laquelle on peut appliquer les mêmes opérations
que n’importe quel autre élément du langage

 Une fonction doit posséder une identité intrinsèque lui permettant


d’être passée en paramètre d’une autre fonction ou retournée par
une autre fonction

3 M1 - ENSI - TPA - F.KBOUBI

Fonction d’ordre supérieur (Higher Order Function)

 Une fonction qui accepte une ou plusieurs autres fonctions en

paramètres et qui retourne une fonction

 Une approche fonctionnelle favorise la représentation d’une

application comme un appel chaîné de fonctions pouvant prendre

elles-mêmes des fonctions en paramètres.

4 M1 - ENSI - TPA - F.KBOUBI

2
Expression Lambda et Interfaces
fonctionnelles
Mastère de recherche M1- ENSI
F.Kboubi , ferihane.kboubi@ensi-uma.tn

Pourquoi les lambdas


 Les limites du tout objet à la Java
 Impossible de définir une fonction en dehors d’une classe

 Impossible de passer une fonction en paramètre d’une méthode

=> utilisation des classes internes anonymes (e.g. GUI)

=> beaucoup de lignes pour peu de choses

 Introduction des lambdas en Java 8


 Simplifier / clarifier le code

 Syntaxe proche de la programmation fonctionnelle

6 M1 - ENSI - TPA - F.KBOUBI

3
Interface fonctionnelle
 Elle ne doit avoir qu'une seule méthode déclarée abstraite
public interface InterfaceFonctionnel {
public void show();
}

 Les méthodes définies dans la classe Object ne sont pas prises en compte
comme étant des méthodes abstraites
 Elle peut avoir des méthodes par défaut, ainsi que des méthodes de classe
 Toutes les méthodes doivent être publiques
public interface InterfaceFonctionnel {
public void show();
public default int addition(int a, int b) {
return a + b;
}
public static int soustraction(int a, int b) {
return a - b;
}
}

7 M1 - ENSI - TPA - F.KBOUBI

Interface fonctionnelle
 L'annotation @FunctionalInterface permet d'indiquer explicitement
au compilateur que l'interface est une interface fonctionnelle
 Le compilateur pourra alors vérifier que les contraintes d’une interface fonctionnelles sont
respectées.
 Son utilisation est facultative.

 Les interfaces fonctionnelles peuvent être implémentées par une


expression Lambda

InterfaceFonctionnel lambda = () -> {


System.out.println("Implémentation méthode");
}

8 M1 - ENSI - TPA - F.KBOUBI

4
Usage d’une interface fonctionnelle
 Pour créer un objet qui implémente une interface fonctionnelle il existe trois moyens :
 Écrire une nouvelle classe nommée qui implémente la méthode, et créer un l’objet à partir de cette classe
public Classe implements InterfaceFonctionnel{
public void show() {
System.out.println("Implémentation méthode")
}
}
Classe c=new Classe();
c.show();

 Créer l’objet à partir d’une classe anonyme qui définit la méthode ;


InterfaceFonctionnel c=new InterfaceFonctionnel() {
public void show() {
System.out.println("Implémentation méthode")
}
};
c.show();
 Écrire un expression lambda qui fournit le code de la méthode.
InterfaceFonctionnel lambda = () -> {System.out.println("Implémentation méthode");}

9 M1 - ENSI - TPA - F.KBOUBI

java.util.function
 Afin d’éviter aux développeurs de créer systématiquement leurs interfaces,
le package java.util.function déclare les interfaces fonctionnelles les plus
utiles.
 Les interfaces fonctionnelles dont le nom se termine par:
 Function déclarent une méthode qui prend un ou plusieurs paramètres et qui
retourne un résultat.
 Operator déclarent une méthode qui prend un ou plusieurs paramètres du même
type et retourne un résultat du même type.
 Consumer déclarent une méthode qui prend un ou plusieurs paramètres mais qui ne
retourne aucun résultat.
 Supplier déclarent une méthode qui ne prend aucun paramètre mais qui retourne un
résultat.
 Predicate déclarent une méthode qui prend un paramètre et qui retourne un
résultat de type booléen.

10 M1 - ENSI - TPA - F.KBOUBI

5
java.util.function

11 M1 - ENSI - TPA - F.KBOUBI

Expression Lambda
 Une fonction anonyme sans déclaration explicite du type de retour, ni de
modificateurs d'accès, ni de nom.

 Elle permet de définir une méthode directement à l'endroit où elle est


utilisée.

 Elle est utile lorsque le traitement n'est utilisé qu'une seule fois

 Elle évite d'avoir à écrire une méthode dans une classe.

 Elle permet d'encapsuler un traitement pour être passé à d'autres


traitements.

 C'est un raccourci syntaxique aux classes anonymes internes pour une


interface qui ne possède qu'une seule méthode abstraite.

12 M1 - ENSI - TPA - F.KBOUBI

6
Expression Lambda
 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.

 Elle permet d'écrire du code plus compact et plus lisible.

 Elle ne réduit pas l'aspect orienté objet du langage mais rend celui-ci
plus riche pour certaines fonctionnalités.

13 M1 - ENSI - TPA - F.KBOUBI

La syntaxe des expressions lambda


 La syntaxe d'une expression lambda est composée de trois parties :
 un ensemble de paramètres, d'aucun à plusieurs
 l'opérateur ->
 le corps de la fonction
 Elle peut avoir zéro, un ou plusieurs paramètres

() -> System.out.println("Zéro paramètre");

(a) -> System.out.println("Un seul paramètre: " + a);

(a, b) -> System.out.println("Plusieurs paramètres: " + a + ", " + b);

14 M1 - ENSI - TPA - F.KBOUBI

7
La syntaxe des expressions lambda
 Type facultative : Pas besoin de déclarer le type d’un paramètre. Le
compilateur peut déduire le type de la valeur du paramètre.

 Parenthèses facultatives : Si un seul paramètre

 Accolades facultatives : Si le corps contient une seule instruction.

 Le mot clé « return » est facultatif : Si une seule instruction le compilateur


renvoie automatiquement la valeur de cette instruction

 Plusieurs formes principales :


 paramètre -> expression;
 (paramètres) -> expression;
 (paramètres) -> { traitements; }

15 M1 - ENSI - TPA - F.KBOUBI

Exemple sans interface fonctionnelle

16 M1 - ENSI - TPA - F.KBOUBI

8
Exemple avec interface fonctionnelle
public class Main {
public static void main(String args[]) {
//avec la déclaration de type
Operation addition = (int x, int y) -> x + y;

//sans déclaration de type


Operation soustraction = (x, y) -> x - y;

//avec 'return' et les accolades


Operation multiplication = (int x, int y) -> { return x * y; };

//sans 'return' et sans les accolades


Operation division = (int x, int y) -> x / y;

System.out.println("8 + 2 = " + calculer(8, 2, addition));


System.out.println("8 - 2 = " + calculer(8, 2, soustraction));
System.out.println("8 x 2 = " + calculer(8, 2, multiplication));
System.out.println("8 / 2 = " + calculer(8, 2, division));
}

interface Operation {
int calc(int x, int y);
}

private static int calculer(int x, int y, Operation op) {


return op.calc(x, y);
}
}
17 M1 - ENSI - TPA - F.KBOUBI

Exemple avec interface fonctionnelle


public interface CheckContent {
public boolean test(Content content);

public class Corpus implements Content, Subject{



public void printDocument(CheckContent check) {
for (Content doc:documents) {
if(check.test(doc)) {
System.out.println("OK : "+doc.getName());
}
}
}
}

18 M1 - ENSI - TPA - F.KBOUBI

9
Avec classes anonymes
public class Client {
public static void main(String args[]) {

/* ******************** Classe Interne Anonyme *********************** */


// Afficher les documents dont le nom contient "2"
System.out.println("Classe Anonyme 1");
c.printDocument(new CheckContent(){
public boolean test(Content c) {
return c.getName().contains("2");
}});

// Afficher les documents dont le nom se termine par "e.txt"


System.out.println("Classe Anonyme 2");
CheckContent check=new CheckContent(){
public boolean test(Content c) {
return c.getName().endsWith("e.txt");
}
};
c.printDocument(check);
}
}

19 M1 - ENSI - TPA - F.KBOUBI

Avec Expression Lambda


public class Client {
public static void main(String args[]) {

/* ******************** Lambda Expression *********************** */


// Afficher les documents dont le nom se commence par "data"
System.out.println("Lambda Expression 0");
CheckContent check2=cont->cont.getName().startsWith("data");
c.printDocument(check2);

// Afficher les documents qui contiennent le mot "ligne"


System.out.println("Lambda Expression 1");
c.printDocument(d->d.getVocab().contains("ligne"));

// Afficher les documents dont le nom contient "data"


System.out.println("Lambda Expression 2");
c.printDocument(d->d.getName().contains("data"));

}
}

20 M1 - ENSI - TPA - F.KBOUBI

10
Avec Expression Lambda
public class Client {
public static void main(String args[]) {

/* ******************** Lambda Expression *********************** */

// Afficher les documents qui contiennent le mot "du" avec une fréquence = 2
System.out.println("Lambda Expression 3");
c.printDocument(d->{if(d.getWordFreq().containsKey("du"))
{return d.getWordFreq().get("du")==2;}
else return false;});

// Afficher les documents qui ne contiennent pas les mots <deuxième, un>
System.out.println("Lambda Expression 4");
Set<String> s=new HashSet<String>();s.add("deuxième");s.add("un");
c.printDocument(d->!d.getVocab().containsAll(s));

}
}

21 M1 - ENSI - TPA - F.KBOUBI

Lambda et closure (fermeture)


 Un environnement lexical constitué de toutes les variables et de tous les attributs que la lamda
capture au moment de sa déclaration.

 Le corps d’une lambda peut accéder au contenu d’une variable déclarée dans la closure.

 Mais ne peut pas modifier le contenu d’un paramètre ou d’une variable issue d’une closure

List<String> prenoms = Arrays.asList("Amal", "Yasmine", "Latifa");


List<String> helloList = new ArrayList<>();

prenoms.forEach(e -> helloList.add("Hello " + e));


System.out.println(helloList); // [Hello Amal, Hello Yasmine, Hello Latifa]

List<Integer> liste = Arrays.asList(1,2,3,4);

int i = 0;
liste.forEach(e -> i += e); // ERREUR DE COMPILATION : la variable i ne peut pas
// être modifiée car elle fait partie de la closure.

22 M1 - ENSI - TPA - F.KBOUBI

11
L’opérateur :: de référence de méthode
 L’opérateur :: permet de référencer une méthode en évitant de déclarer une
lambda.
 Rend le code plus lisible

Collection<String> collection = Arrays.asList("un", "deux", "trois");


collection.forEach(e -> System.out.println(e));

Collection<String> collection = Arrays.asList("un", "deux", "trois");


collection.forEach(System.out::println); // passage de la référence de la méthode

23 M1 - ENSI - TPA - F.KBOUBI

La classe Optional
 Dans beaucoup de langages de programmation, nous avons la possibilité d’affecter à
des variables, des paramètres ou des attributs une référence nulle.
 Cela peut conduire à toutes sortes de bugs (NullPointerException en Java)
 Optional permet de représenter la possibilité qu’il existe ou non une valeur sans avoir
besoin d’utiliser null
Optional<String> v = Optional.ofNullable("test");

if (v.isPresent()) {
System.out.println(v);
} else {
System.out.println("valeur non trouvée");
}

Optional<String> v = Optional.ofNullable("test");

//retourne la valeur de l'optional si elle est définie ou la valeur par défaut passée en paramètre.
System.out.println(v.orElse("valeur non trouvée"));

//invoque la méthode passée en référence uniquement si une valeur est définie par l'optional
v.ifPresent(System.out::println);

//retourne la valeur de l'optional si elle est définie ou jette une exception


//construite à partir du constructeur fourni en paramètre.
String resultat = v.orElseThrow(ValeurNonTrouveeException::new);

24 M1 - ENSI - TPA - F.KBOUBI

12
LAMBDA EXPRESSIONS ET API STREAM

25 M1 - ENSI - TPA - F.KBOUBI

API Streams
 L’API streams a été introduite avec Java 8 pour permettre la
programmation fonctionnelle.
 Un stream (flux) est une représentation d’une séquence sur laquelle
il est possible d’appliquer des opérations.
 Elle permet d’effectuer les opérations sur une séquence sans utiliser
de structure de boucle (bonne lisibilité du code)
 Les opérations sur les streams sont réalisées en flux (d’où leur nom)
ce qui limite l’empreinte mémoire nécessaire.
 Il est possible de réaliser des traitements en parallèle pour tirer partie
des possibilités d’un processeur multi-cœurs ou d’une machine
multi-processeurs.

26 M1 - ENSI - TPA - F.KBOUBI

13
Création d’un stream
 On peut créer un Stream en utilisant un objet de type builder
Stream<String> stream = Stream.<String>builder().add("Hello").add("World").build();

IntStream intStream = IntStream.of(1, 20, 30, 579);

IntStream rangeIntStream = IntStream.range(0, 1000);

// Un stream infini, commençant à la valeur 1 et qui est représenté par la suite n = n + 1


LongStream longStream = LongStream.iterate(1, n -> n + 1);

//création d’un stream à partir d’un tableau


int[] tableau = { 1, 2, 3, 4 };
IntStream tableauStream = Arrays.stream(tableau);

//Création d'un stream à partir d'une collection


List<String> liste = Arrays.asList("Hello", "World");
Stream<String> stream = liste.stream();

//Création d'un stream à partir d'un fichier


Path fichier = Paths.get("fichier.txt");
Stream<String> linesStream = Files.lines(fichier);

27 M1 - ENSI - TPA - F.KBOUBI

Méthode filter()
 Méthode filter() permet d’appliquer un filtre pour éliminer
une partie de ses éléments
// On affiche les 500 premiers nombres qui ne sont pas divisibles par 7
IntStream.iterate(1, n -> n + 1)
.filter(n -> n % 7 != 0)
.limit(500)
.forEach(System.out::println);

// On affiche les 500 premiers nombres qui ne sont pas divisibles par 7
// et qui sont impairs
IntStream.iterate(1, n -> n + 1)
.filter(n -> n % 7 != 0)
.filter(n -> n % 2 != 0)
.limit(500)
.forEach(System.out::println);

28 M1 - ENSI - TPA - F.KBOUBI

14
Méthode map()
 Méthode map() permet de transformer la nature du stream afin de
passer d’un type à un autre
List<Voiture> liste = Arrays.asList(new Voiture("citroen"), new Voiture("audi"),
new Voiture("renault"), new Voiture("volkswagen"),
new Voiture("citroen"));

//mapping du stream de voiture en stream de String


Set<String> marques = liste.stream().map(Voiture::getMarque).collect(Collectors.toSet());

System.out.println(marques); // ["audi", "citroen", "renault", "volkswagen"]

Pour réaliser un mapping vers un type primitif, il faut utiliser les


méthodes Stream.mapToInt, Stream.mapToLong ou Stream.mapToDouble.

// Affichage de la racine carré des 100 premiers entiers


IntStream.range(1, 101)
.mapToDouble(Math::sqrt)
.forEach(System.out::println);
}

29 M1 - ENSI - TPA - F.KBOUBI

Méthode reduce()
 Permet d’appliquer une action pour réduire le stream et obtenir un résultat
unique

// Obtenir la chaine la plus longue


List<String> liste = Arrays.asList("une chaine", "une autre chaine", "encore une chaine");
Optional<String> plusLongue = liste.stream()
.reduce((s1, s2) -> s1.length() > s2.length() ? s1 : s2);

System.out.println(plusLongue.orElse("Liste vide"));

30 M1 - ENSI - TPA - F.KBOUBI

15
Méthode collect()
 Permet de créer une nouvelle collection à partir d’un stream
List<String> liste = Arrays.asList("une chaine", "une autre chaine", "encore une chaine");
List<String> autreListe = liste.stream().collect(Collectors.toList());

List<Voiture> liste = Arrays.asList(new


public class Voiture {
Voiture("citroen"),
new Voiture("renault"),
private String marque;
new Voiture("audi"),
new Voiture("citroen"));
public Voiture(String marque) {
this.marque = marque;
Map<String, List<Voiture>> map =
}
liste.stream().collect(Collectors.groupingBy(Voiture
::getMarque));
public String getMarque() {
return marque;
System.out.println(map.get("citroen").size()); // 2
}
System.out.println(map.get("renault").size()); // 1
}
System.out.println(map.get("audi").size()); // 1

List<String> list = Arrays.asList("un", "deux", "trois", "quatre", "cinq");


String resultat = list.stream().collect(Collectors.joining(", "));

System.out.println(resultat); // "un, deux, trois, quatre, cinq"

31 M1 - ENSI - TPA - F.KBOUBI

Méthode limit(), skip(), sorted()


 limit() limite de nombre d’éléments du stream à n.
 skip() saute n éléments du stream
 sorted() permet de trier les éléments d’un stream

IntStream.range(1, 100).map(v->2*v).limit(10).forEach(System.out::println);

IntStream.range(1, 100).map(v->2*v).skip(10).forEach(System.out::println);

32 M1 - ENSI - TPA - F.KBOUBI

16
Méthode allMatch(), anyMatch(),noneMatch()
 allMatch(), s’assure que tous les éléments du stream vérifient la
condition
List<String> names=Arrays.asList("John","Joe","Jack","Jane");
Boolean check=names.stream().allMatch(v->v.startsWith("J"));
System.out.println(check);

 anyMatch(), s’assure qu’au moins un élément du stream vérifie la


condition
List<String> fruits=Arrays.asList("apple","grape","banana","orange");
Boolean check=fruits.stream().anyMatch(v->v.equals("orange"));
System.out.println(check);

 noneMatch() s’assure qu’aucun élément du stream ne vérifie la


condition
List<String> fruits=Arrays.asList("apple","grape","banana","orange");
Boolean check=fruits.stream().noneMatch(v->v.equals("ananas"));
System.out.println(check);

33 M1 - ENSI - TPA - F.KBOUBI

Méthode forEach()
 Permet d’appliquer un traitement sur chaque élément du stream

Programmation fonctionnelle et Lambda expression

Collection<String> collection = new ArrayList<>();


collection.add("un");
collection.add("deux");
collection.add("trois");

collection.forEach(e -> System.out.println(e));

Programmation impérative

Collection<String> collection = new ArrayList<>();


collection.add("un");
collection.add("deux");
collection.add("trois");

for(String e : collection) {
System.out.println(e);
}

34 M1 - ENSI - TPA - F.KBOUBI

17
Méthode parallel()
 Un stream en parallèle découpe le flux pour assigner
l’exécution à différents processeurs et recombine ensuite
le résultat à la fin.
 Cela signifie que les traitements sur le stream ne doivent
pas être dépendant de l’ordre d’exécution.

IntStream.range(1, 10).parallel().map(v->2*v).forEach(System.out::println);

35 M1 - ENSI - TPA - F.KBOUBI

Exercice

36 M1 - ENSI - TPA - F.KBOUBI

18
37 M1 - ENSI - TPA - F.KBOUBI

38 M1 - ENSI - TPA - F.KBOUBI

19

Vous aimerez peut-être aussi