[Go to site: main page, start]

0% ont trouvé ce document utile (0 vote)
0 vues27 pages

Java Interfaces Fonctionnelles Guide Complet

java

Transféré par

tagnelavoisier
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
0 vues27 pages

Java Interfaces Fonctionnelles Guide Complet

java

Transféré par

tagnelavoisier
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

POO Java · [Link].

function · Lambda · Method Reference

Guide Complet & Détaillé

À propos de ce guide

Ce guide couvre en profondeur les interfaces fonctionnelles de Java 8+. Vous y découvrirez les
quatre familles fondamentales (Function, Predicate, Consumer, Supplier), les interfaces spécialisées
(BiFunction, UnaryOperator…), les expressions lambda, les références de méthodes, la composition
de fonctions et les bonnes pratiques professionnelles. Chaque concept est illustré par des exemples
de code commentés ligne par ligne.

@FunctionalInterfa
Java 8+ Fonctionnel Lambda ce

Interfaces Fonctionnelles Java — Guide Complet Page 1


POO Java · [Link] · Lambda · Method Reference

Table des Matières

1. Fondements des Interfaces Fonctionnelles 3

1.1 Définition et annotation @FunctionalInterface 3

1.2 Les expressions Lambda 3

1.3 Les références de méthodes (Method References) 4

2. Les 4 Familles Fondamentales 5

2.1 Function — Transformer 5

2.2 Predicate — Tester 6

2.3 Consumer — Consommer 7

2.4 Supplier — Fournir 8

3. Interfaces Bi-arité 9

3.1 BiFunction 9

3.2 BiPredicate 9

3.3 BiConsumer 10

4. Interfaces Spécialisées & Opérateurs 10

4.1 UnaryOperator et BinaryOperator 10

4.2 Interfaces primitives (IntFunction, ToIntFunction…) 11

5. Composition de Fonctions 12

5.1 Composition avec Function : andThen, compose 12

5.2 Composition avec Predicate : and, or, negate 13

5.3 Composition avec Consumer : andThen 13

6. Créer ses propres Interfaces Fonctionnelles 14

7. Interfaces Fonctionnelles & Streams 15

8. Exemple Complet Réaliste 17

9. Tableau Récapitulatif & Bonnes Pratiques 19

Interfaces Fonctionnelles Java — Guide Complet Page 2


POO Java · [Link] · Lambda · Method Reference

1. Fondements des Interfaces Fonctionnelles

1.1 Définition et annotation @FunctionalInterface

Une interface fonctionnelle est une interface qui ne possède qu'une seule méthode abstraite. Elle peut
avoir des méthodes default ou static en nombre illimité, mais une seule méthode abstraite. L'annotation
@FunctionalInterface est optionnelle mais recommandée : elle demande au compilateur de vérifier
cette contrainte.

// Déclaration d'une interface fonctionnelle


personnalisée

@FunctionalInterface // annotation optionnelle mais


recommandée

public interface Calculatrice {

int calculer(int a, int b); // unique méthode abstraite

// Les méthodes default et static sont autorisées

default void afficherResultat(int a, int b) { // méthode par défaut — ne compte


pas

[Link]("Résultat : " + calculer(a,


b));

static Calculatrice addition() { // méthode statique — ne compte pas


non plus

return (a, b) -> a + b; // lambda retournant une instance

// Utilisation

Calculatrice mult = (a, b) -> a * b; // implémentation via lambda

Calculatrice add = [Link](); // via méthode statique

[Link]([Link](3, 4)); // 12

[Link](5, 3); // Résultat : 8

■ Note

Avant Java 8, implémenter une interface nécessitait une classe anonyme. Les interfaces fonctionnelles
permettent de les remplacer par des lambdas, rendant le code bien plus concis.

1.2 Les Expressions Lambda

Interfaces Fonctionnelles Java — Guide Complet Page 3


POO Java · [Link] · Lambda · Method Reference

Une expression lambda est une implémentation concise d'une interface fonctionnelle. Sa syntaxe est :
(paramètres) -> corps. Elle peut remplacer toute classe anonyme implémentant une interface
fonctionnelle.

// ■■ Syntaxe des lambdas


■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

// Pas de paramètre

Runnable r = () -> [Link]("Bonjour"); // parenthèses vides obligatoires

// Un paramètre : parenthèses optionnelles

Consumer c1 = s -> [Link](s); // parenthèses omises (1 param)

Consumer c2 = (s) -> [Link](s); // parenthèses présentes


(équivalent)

Consumer c3 = (String s) -> // type explicite (rarement


[Link](s); nécessaire)

// Deux paramètres : parenthèses obligatoires

BiFunction somme = (a, b) -> a + b; // corps = expression directe

// Corps avec plusieurs instructions : accolades


+ return

Function traiter = (s) -> {

String trimmed = [Link](); // instruction 1

String upper = [Link](); // instruction 2

return upper; // return obligatoire avec


accolades

};

// Lambda qui capture une variable externe


(effectively final)

String prefixe = "Hello, "; // variable locale — doit être


effectively final

Function saluer = nom -> prefixe + nom; // capture de prefixe

[Link]([Link]("Alice")); // "Hello, Alice"

1.3 Références de Méthodes (Method References)

Les références de méthodes sont un raccourci syntaxique pour les lambdas qui ne font qu'appeler une
méthode existante. Il en existe quatre types, selon la cible appelée.

Type Syntaxe Équivalent lambda Exemple

Méthode statique Classe::méthode (args) -> Classe.méthode(args)


Integer::parseInt

Interfaces Fonctionnelles Java — Guide Complet Page 4


POO Java · [Link] · Lambda · Method Reference

Méthode d'instance
objet::méthode (args) -> objet.méthode(args)
[Link]::println
(objet connu)

Méthode d'instance
Classe::méthode (obj, args) -> obj.méthode(args)
String::toUpperCase
(type connu)

Constructeur Classe::new (args) -> new Classe(args) ArrayList::new

// ■■ Les 4 types de références de méthodes


■■■■■■■■■■■■■■■■■

// 1. Méthode statique : Classe::méthodeStatique

Function parser = Integer::parseInt; // équivalent : s ->


[Link](s)

[Link]([Link]("42")); // 42

// 2. Méthode d'instance sur un objet spécifique

PrintStream ps = [Link]; // objet connu à l'avance

Consumer afficher = ps::println; // équivalent : s -> [Link](s)

[Link]("Bonjour"); // affiche "Bonjour"

// 3. Méthode d'instance sur un objet du type


générique

Function upper = String::toUpperCase; // équivalent : s -> [Link]()

Function length = String::length; // équivalent : s -> [Link]()

// 4. Constructeur : Classe::new

Supplier> factory = ArrayList::new; // équivalent : () -> new


ArrayList<>()

ArrayList liste = [Link](); // crée une nouvelle ArrayList

Function sbFactory = StringBuilder::new; // constructeur avec paramètre

StringBuilder sb = [Link]("Hello"); // new StringBuilder("Hello")

Interfaces Fonctionnelles Java — Guide Complet Page 5


POO Java · [Link] · Lambda · Method Reference

2. Les 4 Familles Fondamentales de [Link]

Le package [Link] contient 43 interfaces fonctionnelles organisées autour de 4 familles


fondamentales. Comprendre ces 4 familles suffit pour maîtriser toutes les autres, car les variantes en
découlent directement.

Famille Signature Méthode abstraite Rôle

Function<T,R> T → R R apply(T t) Transformer une valeur

Predicate<T> T → boolean boolean test(T t) Tester une condition

Consumer<T> T → void void accept(T t) Consommer sans retour

Supplier<T> () → T T get() Fournir une valeur

2.1 Function — Transformer une entrée en sortie

Function [Link]

Signature : Function Méthode abstraite : R apply(T t)

Représente une fonction qui accepte un argument de type T et produit un résultat de type R. C'est
l'interface la plus générale pour toute transformation. T et R peuvent être du même type ou de types
différents.

// ■■ Function : transforme T en R
■■■■■■■■■■■■■■■■■■■■■■■

// String → Integer : longueur de la chaîne

Function longueur = String::length; // référence de méthode

[Link]([Link]("Bonjour")); // 7

// Integer → String : conversion en binaire

Function toBin = n -> [Link](n); // n → représentation binaire

[Link]([Link](10)); // "1010"

// String → String : même type en entrée et


sortie

Function normaliser = s -> // trim + minuscules


[Link]().toLowerCase();

[Link]([Link](" JAVA ")); // "java"

// Objet métier → autre objet métier

record Employe(String nom, int age) {}

Interfaces Fonctionnelles Java — Guide Complet Page 6


POO Java · [Link] · Lambda · Method Reference

record EmployeDTO(String nomComplet, String // Data Transfer Object


categorie) {}

Function toDTO = e -> new EmployeDTO(

[Link]().toUpperCase(), // nom en majuscules

[Link]() >= 30 ? "Senior" : "Junior"); // catégorie selon l'âge

EmployeDTO dto = [Link](new Employe("Alice",


35));

// dto = EmployeDTO("ALICE", "Senior")

// ■■ andThen : enchaîner deux Function


■■■■■■■■■■■■■■■■■■■■■

Function f1 = String::length; // String → Integer

Function f2 = n -> n > 5; // Integer → Boolean

Function f3 = [Link](f2); // String → Boolean (chaînage)

[Link]([Link]("Bonjour")); // true (longueur 7 > 5)

2.2 Predicate — Tester une condition

Predicate [Link]

Signature : Predicate Méthode abstraite : boolean test(T t)

Représente une condition (prédicat) qui prend un argument de type T et retourne un boolean. Très utilisé
avec les Streams (filter), les Collections et pour exprimer des règles métier. Supporte la composition
logique (and, or, negate).

// ■■ Predicate : teste une condition sur T


■■■■■■■■■■■■■■■

// Prédicats simples

Predicate estVide = String::isEmpty; // vrai si la chaîne est vide

Predicate estPositif = n -> n > 0; // vrai si n > 0

Predicate commenceParA = s -> [Link]("A"); // vrai si commence par "A"

[Link]([Link]("")); // true

[Link]([Link](-5)); // false

// ■■ Composition logique
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

Predicate nonVide = [Link](); // inverse le prédicat : non vide

Predicate nonVideEtA = [Link](commenceParA); // non vide ET commence par A

Predicate videOuA = [Link](commenceParA); // vide OU commence par A

Interfaces Fonctionnelles Java — Guide Complet Page 7


POO Java · [Link] · Lambda · Method Reference

[Link]([Link]("Alice")); // true : non vide ✓ et commence


par A ✓

[Link]([Link]("Bob")); // false : commence par B

[Link]([Link]("")); // true : vide ✓

// ■■ [Link]() (Java 11+)


■■■■■■■■■■■■■■■■■■■■■■■■■■■■

Predicate nonVideV2 = // syntaxe plus lisible avec


[Link](String::isEmpty); référence de méthode

// ■■ Utilisation dans un contexte métier


■■■■■■■■■■■■■■■■■■■■

record Produit(String nom, double prix, int


stock) {}

Predicate disponible = p -> [Link]() > 0; // en stock

Predicate abordable = p -> [Link]() < 50.0; // prix < 50€

Predicate bonAffaire = [Link](abordable); // en stock ET abordable

List produits = [Link](

new Produit("Livre", 12.0, 5),

new Produit("Ordi", 800.0, 2),

new Produit("Stylo", 3.0, 0)); // stock = 0 → indisponible

[Link]()

.filter(bonAffaire) // filtre composé : dispo ET


abordable

.map(Produit::nom)

.forEach([Link]::println); // affiche uniquement "Livre"

2.3 Consumer — Consommer sans retour

Consumer [Link]

Signature : Consumer Méthode abstraite : void accept(T t)

Représente une opération qui accepte un seul argument de type T et ne retourne rien (void). Typiquement
utilisé pour les effets de bord : affichage, écriture en base, envoi d'email, journalisation. Méthode de
composition : andThen() pour chaîner des consumers.

// ■■ Consumer : consomme T, ne retourne rien


■■■■■■■■■■■■■

// Consumer simple : affichage

Consumer afficher = [Link]::println; // référence de méthode sur instance

Interfaces Fonctionnelles Java — Guide Complet Page 8


POO Java · [Link] · Lambda · Method Reference

[Link]("Bonjour Java"); // affiche "Bonjour Java"

// Consumer avec logique métier

Consumer logger = msg -> {

String timestamp = [Link]().toString(); // heure actuelle

[Link]("[%s] %s%n", timestamp, msg); // format [HH:mm:ss] message

};

// ■■ andThen : chaîner deux consumers


■■■■■■■■■■■■■■■■■■■■■■

Consumer sauvegarder = msg -> // sauvegarde dans un fichier


[Link](msg); (pseudo-code)

Consumer logEtSauve = // exécute logger PUIS sauvegarder


[Link](sauvegarder);

[Link]("Erreur critique"); // 1. affiche avec timestamp 2.


sauvegarde

// ■■ Exemple concret : traitement d'une liste


■■■■■■■■■■■■■■

record Client(String nom, String email, boolean


premium) {}

Consumer envoyerEmail = c -> // envoi email (pseudo-code)


[Link]([Link]());

Consumer afficherInfo = c ->

[Link]([Link]() + " | " + [Link]()); // afficher les infos

Consumer marquerTraite = c -> // marquer en base (pseudo-code)


[Link]([Link]());

// Pipeline de consumers : email → afficher →


marquer

Consumer pipeline = envoyerEmail

.andThen(afficherInfo) // enchaîné

.andThen(marquerTraite); // enchaîné

List clients = /* ... */ null;

[Link]()

.filter(Client::premium) // uniquement les clients premium

.forEach(pipeline); // applique le pipeline à chacun

2.4 Supplier — Fournir une valeur sans argument

Supplier [Link]

Interfaces Fonctionnelles Java — Guide Complet Page 9


POO Java · [Link] · Lambda · Method Reference

Signature : Supplier Méthode abstraite : T get()

Représente un fournisseur de résultat de type T. N'accepte aucun paramètre et retourne une valeur. Très
utile pour la création lazy d'objets coûteux, les valeurs par défaut (avec [Link]), les factories.

// ■■ Supplier : fournit T sans argument


■■■■■■■■■■■■■■■■■■

// Suppliers simples

Supplier hello = () -> "Hello, World!"; // retourne toujours la même chaîne

Supplier aleatoire = Math::random; // référence de méthode statique

Supplier today = LocalDate::now; // date du jour au moment de l'appel

Supplier> newList = ArrayList::new; // référence de constructeur

[Link]([Link]()); // "Hello, World!"

[Link]([Link]()); // ex: 0.7823...

// ■■ Cas d'usage : création lazy (coût différé)


■■■■■■■■■■■■■

// L'objet ConfigLourde n'est créé QUE si


nécessaire

Supplier config = ConfigLourde::charger; // la config n'est PAS chargée ici

if (modeDebug) {

ConfigLourde cfg = [Link](); // chargée uniquement si modeDebug =


true

[Link]();

// ■■ Avec [Link] (lazy vs orElse)


■■■■■■■■■■■■■■■

Optional opt = [Link]();

// orElse : TOUJOURS évalue l'expression (même si


opt présent)

String r1 = [Link](creerValeurCouteuse()); // creerValeurCouteuse() est


TOUJOURS appelée

// orElseGet : N'évalue QUE si opt est vide


(lazy)

String r2 = [Link](() -> // appelé SEULEMENT si opt est vide


creerValeurCouteuse()); → performant

// ■■ Factory via Supplier


■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

Map> animalFactory = new HashMap<>();

Interfaces Fonctionnelles Java — Guide Complet Page 10


POO Java · [Link] · Lambda · Method Reference

[Link]("chat", Chat::new); // référence de constructeur

[Link]("chien", Chien::new);

[Link]("lapin", Lapin::new);

Animal a = [Link]("chat").get(); // crée un Chat à la demande

Interfaces Fonctionnelles Java — Guide Complet Page 11


POO Java · [Link] · Lambda · Method Reference

3. Interfaces Bi-arité — Deux arguments

Pour les opérations nécessitant deux arguments en entrée, Java fournit les variantes Bi- des interfaces
fondamentales. Elles sont limitées à deux arguments (pas de Tri- ou plus ; utilisez un objet composite
au-delà).

3.1 BiFunction — Deux entrées, une sortie

// BiFunction : (T, U) → R

// Concaténation de deux chaînes

BiFunction concat = (a, b) -> a + " " + b;

[Link]([Link]("Bonjour", // "Bonjour Alice"


"Alice"));

// Calcul d'un indice composite

BiFunction imc =

(poids, taille) -> poids / [Link](taille / // poids(kg) / taille²(m)


100.0, 2);

[Link]("IMC: %.2f%n", [Link](70, // IMC: 22.86


175));

// Création d'un objet à partir de deux valeurs

BiFunction creerEmploye =

(nom, age) -> new Employe(nom, age);

// Ou plus concis :

BiFunction creerE2 = Employe::new; // référence de constructeur


bi-paramètre

Employe e = [Link]("Bob", 28); // new Employe("Bob", 28)

// andThen sur BiFunction

BiFunction longueurConcat =

[Link](String::length); // concat → String, puis length →


Integer

[Link]([Link]("Hi", // 7 (longueur de "Hi Java")


"Java"));

3.2 BiPredicate — Tester deux valeurs

// BiPredicate : (T, U) → boolean

BiPredicate estAssezLong =

Interfaces Fonctionnelles Java — Guide Complet Page 12


POO Java · [Link] · Lambda · Method Reference

(s, longueurMin) -> [Link]() >= longueurMin; // s a au moins longueurMin


caractères

[Link]([Link]("Java", // true (4 >= 3)


3));

[Link]([Link]("OK", 5)); // false (2 < 5)

// BiPredicate dans un contexte de validation

BiPredicate contient =

(texte, motCle) -> // recherche insensible à la casse


[Link]().contains(motCle);

// Composition : and, or, negate (mêmes que


Predicate)

BiPredicate sommePositive = (a, b) -> a + b > 0;

BiPredicate produitPositif = (a, b) -> a * b > 0;

BiPredicate deuxPositifs = // ET logique


[Link](produitPositif);

3.3 BiConsumer — Consommer deux valeurs

// BiConsumer : (T, U) → void

BiConsumer afficher =

(nom, age) -> [Link]("%s a %d ans%n", // formate et affiche


nom, age);

[Link]("Alice", 30); // "Alice a 30 ans"

// BiConsumer avec une Map — cas d'usage typique

Map scores = new HashMap<>();

BiConsumer ajouterScore = scores::put; // référence de méthode d'instance

[Link]("Alice", 95); // [Link]("Alice", 95)

[Link]("Bob", 87); // [Link]("Bob", 87)

// forEach sur Map attend un BiConsumer

[Link]((nom, score) -> // [Link] prend un BiConsumer

[Link]("%-10s : %d%n", nom, score)); // affiche chaque entrée de la map

Interfaces Fonctionnelles Java — Guide Complet Page 13


POO Java · [Link] · Lambda · Method Reference

4. Interfaces Spécialisées & Opérateurs

4.1 UnaryOperator et BinaryOperator

UnaryOperator<T> est une spécialisation de Function<T,T> pour le cas où le type d'entrée et de sortie
sont identiques. BinaryOperator<T> est une spécialisation de BiFunction<T,T,T>.

// UnaryOperator extends Function

// Utilisé quand on transforme T en T (même type)

UnaryOperator trim = String::trim; // String → String

UnaryOperator upper = String::toUpperCase; // String → String

UnaryOperator doubler = n -> n * 2; // Integer → Integer

UnaryOperator carrer = n -> n * n; // Integer → Integer

[Link]([Link](" hello ")); // "hello"

// Composition : andThen et compose

UnaryOperator normaliser =

((UnaryOperator) String::trim) // cast nécessaire pour la


composition

.andThen(String::toLowerCase); // trim puis toLowerCase

[Link]([Link](" JAVA ")); // "java"

// Utilisation dans [Link]

List noms = new


ArrayList<>([Link]("alice","BOB","Charlie"));

[Link](s ->
[Link](0,1).toUpperCase() +
[Link](1).toLowerCase());

// noms = ["Alice", "Bob", "Charlie"] // capitalize chaque nom

// ■■ BinaryOperator extends BiFunction


■■■■■■■■■■■

BinaryOperator somme = (a, b) -> a + b; // Integer × Integer → Integer

BinaryOperator max = Integer::max; // référence de méthode statique

BinaryOperator plus_long = (a,b) -> // garde la plus longue


[Link]()>=[Link]() ? a : b;

[Link]([Link](5, 3)); // 8

[Link]([Link](10, 7)); // 10

// BinaryOperator dans [Link]

Interfaces Fonctionnelles Java — Guide Complet Page 14


POO Java · [Link] · Lambda · Method Reference

int total = [Link](1,2,3,4,5).stream().reduce(0, // sum = 15 via BinaryOperator


somme);

String plusLong = // "bonjour"


[Link]("a","bonjour","hi").reduce("",
plus_long);

4.2 Interfaces primitives — Éviter le boxing/unboxing

Java fournit des variantes spécialisées pour éviter le coûteux boxing (int → Integer). Il existe des variantes
pour int, long et double.

Interface Équivalent générique Méthode Cas d'usage

IntFunction<R> Function<Integer,R> R apply(int v) int → objet

ToIntFunction<T> Function<T,Integer> int applyAsInt(T t) objet → int

IntUnaryOperator UnaryOperator<Integer> int applyAsInt(int v)int → int

IntBinaryOperator BinaryOperator<Integer> int applyAsInt(i,j) int,int → int

IntConsumer Consumer<Integer> void accept(int v) consommer un int

IntSupplier Supplier<Integer> int getAsInt() fournir un int

IntPredicate Predicate<Integer> boolean test(int v) tester un int

ToDoubleFunction<T> Function<T,Double> double applyAsDouble objet → double

LongToIntFunction Function<Long,Integer> int applyAsInt(long) long → int

// Exemple : IntPredicate — plus rapide que


Predicate

IntPredicate estPair = n -> n % 2 == 0; // pas de boxing int→Integer

IntPredicate estGrand = n -> n > 100;

IntPredicate pairEtGrand = [Link](estGrand); // composition

[Link]([Link](102)); // true (pair et > 100)

// ToIntFunction : objet → int primitif

ToIntFunction longueur = String::length; // String → int (pas Integer)

int l = [Link]("Bonjour"); // 7 — pas de boxing

// IntBinaryOperator dans [Link]

int[] tableau = new int[10];

[Link](tableau, i -> i * i); // remplit tableau[i] = i²

// tableau = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Interfaces Fonctionnelles Java — Guide Complet Page 15


POO Java · [Link] · Lambda · Method Reference

5. Composition de Fonctions

L'une des grandes puissances des interfaces fonctionnelles est la composition : assembler plusieurs
fonctions simples pour créer des comportements complexes. Chaque interface fonctionnelle propose ses
propres méthodes de composition.

5.1 Composition avec Function : andThen et compose

[Link](g) : applique f d'abord, puis g sur le résultat. Ordre : f → g. [Link](g) : applique g


d'abord, puis f sur le résultat. Ordre : g → f. C'est l'ordre mathématique f■g.

Function fois2 = n -> n * 2; // multiplie par 2

Function plus3 = n -> n + 3; // ajoute 3

Function toStr = n -> "val=" + n; // convertit en String

// andThen : f PUIS g (gauche → droite)

Function fois2PuisPlus3 = [Link](plus3);

[Link]([Link](5)); // 5*2=10, 10+3=13

// compose : g PUIS f (droite → gauche)

Function plus3PuisFois2 = [Link](plus3);

[Link]([Link](5)); // 5+3=8, 8*2=16

// Chaîner plusieurs fonctions : pipeline de


transformations

Function pipeline = ((Function)

String::trim) // 1. supprimer les espaces

.andThen(String::toLowerCase) // 2. mettre en minuscules

.andThen(s -> [Link](" ", "_")); // 3. remplacer espaces par _

[Link]([Link](" Bonjour // "bonjour_monde"


Monde "));

// [Link]() — retourne l'argument tel


quel

Function identite = [Link](); // équivalent à : x -> x

[Link]([Link]("Java")); // "Java" inchangé

// Pipeline complet avec types mixtes

Function trim = String::trim;

Function parse = Integer::parseInt;

Function grand = n -> n > 100;

Interfaces Fonctionnelles Java — Guide Complet Page 16


POO Java · [Link] · Lambda · Method Reference

Function estGrand = // String → Boolean


[Link](parse).andThen(grand);

[Link]([Link](" 150 ")); // true : 150 > 100

[Link]([Link](" 42 ")); // false : 42 <= 100

5.2 Composition avec Predicate : and, or, negate

// Prédicats de base

Predicate estPair = n -> n % 2 == 0;

Predicate estPositif = n -> n > 0;

Predicate estGrand = n -> n > 100;

// and : ET logique (les deux doivent être vrais)

Predicate pairEtPositif = // p1 AND p2


[Link](estPositif);

[Link]([Link](4)); // true (4 est pair ET positif)

[Link]([Link](-4)); // false (-4 n'est pas positif)

// or : OU logique (au moins un doit être vrai)

Predicate pairOuGrand = [Link](estGrand); // p1 OR p2

[Link]([Link](101)); // true (impair mais > 100)

[Link]([Link](4)); // true (pair)

[Link]([Link](3)); // false (impair ET <= 100)

// negate : NON logique (inverse le prédicat)

Predicate estImpair = [Link](); // NOT estPair

[Link]([Link](3)); // true

[Link]([Link](4)); // false

// Composition complexe : règle métier

Predicate regleMetier = estPositif

.and(estPair) // ET pair

.and([Link]()); // ET pas trop grand (<=100)

// Accepte : 2, 4, 6, ..., 100. Refuse : -2, 3,


102, ...

5.3 Composition avec Consumer : andThen

Consumer logger = s -> [Link]("[LOG]


" + s);

Consumer archiver = s -> [Link](s); // pseudo-code

Interfaces Fonctionnelles Java — Guide Complet Page 17


POO Java · [Link] · Lambda · Method Reference

Consumer notifier = s -> // pseudo-code


[Link](s);

// andThen chaîne les consumers séquentiellement

Consumer complet = // log → archive → notif


[Link](archiver).andThen(notifier);

[Link]("Transaction #1234 validée"); // exécute les 3 dans l'ordre

// 1. [LOG] Transaction #1234 validée

// 2. archivée

// 3. notification envoyée

// Utilisation avec forEach

[Link]("event1","event2","event3")

.forEach(complet); // applique le pipeline à chaque


événement

Interfaces Fonctionnelles Java — Guide Complet Page 18


POO Java · [Link] · Lambda · Method Reference

6. Créer ses propres Interfaces Fonctionnelles

Bien que les 43 interfaces de [Link] couvrent la plupart des besoins, il est parfois utile de créer
ses propres interfaces fonctionnelles pour exprimer l'intention métier, gérer des exceptions vérifiées
ou accepter plus de deux paramètres.

// ■■ Cas 1 : Exprimer une intention métier


■■■■■■■■■■■■■■■■■

@FunctionalInterface

public interface Validateur { // plus expressif que Predicate

boolean valider(T valeur); // méthode nommée selon le domaine

default Validateur et(Validateur autre) { // méthode de composition

return valeur -> [Link](valeur) &&


[Link](valeur);

Validateur nonVide = s -> ![Link]();

Validateur email = s -> [Link]("@");

Validateur emailValide = [Link](email);

[Link]([Link]("test@mai // true
[Link]"));

[Link]([Link]("")); // false

// ■■ Cas 2 : Gérer les exceptions vérifiées


■■■■■■■■■■■■■■■■■

@FunctionalInterface

public interface FunctionAvecException {

R apply(T t) throws E; // méthode qui peut lever E

// Utilitaire : wrapper pour les lambdas qui


lèvent des exceptions

static Function wrap(

FunctionAvecException f) {

return t -> {

try { return [Link](t); }

catch (Exception e) { throw new


RuntimeException(e); }

};

Interfaces Fonctionnelles Java — Guide Complet Page 19


POO Java · [Link] · Lambda · Method Reference

// Utilisation : parser un fichier (lève


IOException)

Function lireFichier =

[Link](path -> // IOException wrappée


[Link]([Link](path)));

// ■■ Cas 3 : Plus de 2 paramètres


■■■■■■■■■■■■■■■■■■■■■■■■■■

@FunctionalInterface

public interface TriFunction { // Function à 3 paramètres

R apply(A a, B b, C c); // aucun équivalent dans


[Link]

TriFunction creerTag =

(nom, priorite, actif) ->

[Link]("[%s|P%d|%s]", nom, priorite,

actif ? "ON" : "OFF");

[Link]([Link]("feature", 1, // "[feature|P1|ON]"
true));

Interfaces Fonctionnelles Java — Guide Complet Page 20


POO Java · [Link] · Lambda · Method Reference

7. Interfaces Fonctionnelles & Streams

Les Streams Java utilisent massivement les interfaces fonctionnelles. Chaque méthode du Stream API
attend une interface fonctionnelle spécifique. Voici la correspondance complète, avec des exemples
détaillés.

Méthode Stream Interface attendue Signature Rôle

filter() Predicate<T> T → boolean Garder si vrai

map() Function<T,R> T → R Transformer

flatMap() Function<T,Stream<R>> T → Stream<R> Transformer + aplatir

forEach() Consumer<T> T → void Consommer chaque élément

peek() Consumer<T> T → void Observer sans modifier

sorted() Comparator<T> (T,T) → int Comparer pour trier

reduce() BinaryOperator<T> (T,T) → T Réduire en une valeur

mapToInt() ToIntFunction<T> T → int Convertir en IntStream

mapToObj() IntFunction<R> int → R IntStream → Stream<R>

generate() Supplier<T> () → T Fournir des éléments

collect() Collector<T,A,R> complexe Accumuler le résultat

anyMatch() Predicate<T> T → boolean Tester (court-circuit)

[Link](T) (varargs) T... Créer un stream

Exemple complet : pipeline Stream avec interfaces nommées

record Article(String titre, String categorie,


double prix, int vues) {}

List articles = [Link](

new Article("Java 21", "Tech", 29.99, 5200),

new Article("Cuisine", "Loisir", 19.50, 1800),

new Article("Python", "Tech", 24.99, 4300),

new Article("Jardinage", "Loisir", 14.90, 900),

new Article("Spring", "Tech", 34.99, 6100));

// ■■ Interfaces fonctionnelles nommées


(lisibilité maximale) ■

Predicate estTech = a -> // Predicate


"Tech".equals([Link]());

Predicate estPopulaire = a -> [Link]() > 3000; // Predicate

Interfaces Fonctionnelles Java — Guide Complet Page 21


POO Java · [Link] · Lambda · Method Reference

Function toResume = a -> // Function

[Link]("%-15s %.2f€ (%d vues)", [Link](),


[Link](), [Link]());

Comparator parVues = // Comparator


[Link](Article::vues);

Consumer afficher = [Link]::println; // Consumer

// Pipeline lisible : chaque étape utilise une


interface nommée

[Link]()

.filter(estTech) // Predicate : garder les Tech

.filter(estPopulaire) // Predicate : garder les populaires

.sorted([Link]()) // Comparator : du plus vu au moins


vu

.map(toResume) // Function : transformer en String


résumé

.forEach(afficher); // Consumer : afficher

// Affichage :

// Spring 34.99€ (6100 vues)

// Java 21 29.99€ (5200 vues)

// Python 24.99€ (4300 vues)

Interfaces Fonctionnelles Java — Guide Complet Page 22


POO Java · [Link] · Lambda · Method Reference

8. Exemple Complet et Réaliste

Voici un système de traitement de commandes e-commerce qui combine toutes les interfaces
fonctionnelles vues dans ce guide.

Modèle de données :

enum Statut { EN_ATTENTE, VALIDEE, EXPEDIEE,


LIVREE, ANNULEE }

record Commande(

String id, // identifiant unique

String clientId, // id du client

List articles, // liste des articles commandés

double montant, // montant total en euros

Statut statut, // statut actuel

LocalDate date // date de la commande

) {}

Définition des règles métier avec interfaces fonctionnelles :

public class TraiteurCommandes {

// ■■ Predicates : règles de filtrage


■■■■■■■■■■■■■■■■■■■■

static final Predicate EST_EN_ATTENTE =

c -> [Link]() == Statut.EN_ATTENTE; // statut = EN_ATTENTE

static final Predicate MONTANT_ELEVE =

c -> [Link]() > 500.0; // commande > 500€

static final Predicate RECENTE =

c -> // passée dans les 30 derniers jours


[Link]().isAfter([Link]().minusDays(30));

static final Predicate PRIORITAIRE =

EST_EN_ATTENTE.and(MONTANT_ELEVE).and(RECENTE); // composition de prédicats

// ■■ Functions : transformations
■■■■■■■■■■■■■■■■■■■■■■■■■

static final Function VALIDER =

c -> new Commande([Link](), [Link](),


[Link](),

Interfaces Fonctionnelles Java — Guide Complet Page 23


POO Java · [Link] · Lambda · Method Reference

[Link](), [Link], [Link]()); // nouvelle Commande avec statut


VALIDEE

static final Function VERS_RESUME =

c -> [Link]("[%s] %s → %.2f€ (%s)",

[Link](), [Link](), [Link](), [Link]()); // format lisible

static final Function CALC_TVA =

c -> [Link]() * 0.20; // TVA à 20%

// ■■ Consumers : actions avec effets de bord


■■■■■■■■■■■■■

static final Consumer LOG =

c -> [Link]("[LOG] Traitement : " + // journalisation


[Link]());

static final Consumer ENVOYER_EMAIL =

c -> [Link]([Link](), // pseudo-code

"Commande " + [Link]() + " confirmée");

static final Consumer PIPELINE_NOTIFICATION =

[Link](ENVOYER_EMAIL); // composition de consumers

// ■■ Suppliers ■■■■■■■■■■■■■■■■■■■■■■■■■
■■■■■■■■■■■■■■■■■■■■

static final Supplier GEN_ID =

() -> "CMD-" + // génère un ID unique


[Link]().toString().substring(0,8);

// ■■ UnaryOperator : transformer une commande


■■■■■■■■■■■■■

static final UnaryOperator APPLIQUER_REMISE =

c -> new Commande([Link](), [Link](),


[Link](),

[Link]() * 0.90, [Link](), [Link]()); // 10% de réduction

Traitement du catalogue de commandes :

List commandes = chargerCommandes(); // source de données

// ■■ Traitement 1 : valider les commandes


prioritaires ■■■■■■■■

List validees = [Link]()

.filter(PRIORITAIRE) // Predicate composé

.map(VALIDER) // Function : changer le statut

Interfaces Fonctionnelles Java — Guide Complet Page 24


POO Java · [Link] · Lambda · Method Reference

.peek(PIPELINE_NOTIFICATION) // Consumer : log + email

.collect([Link]()); // collecter les commandes validées

// ■■ Traitement 2 : résumé financier par statut


■■■■■■■■■■■■■

Map chiffreParStatut = [Link]()

.collect([Link](

Commande::statut, // Function implicite via référence

[Link](Commande::montant))); // ToDoubleFunction implicite

// ■■ Traitement 3 : top 5 des plus grandes


commandes ■■■■■■■■■

[Link]()

.filter(EST_EN_ATTENTE) // Predicate

.sorted([Link](Commande::mon // Comparator
tant).reversed())

.limit(5) // les 5 plus grandes

.map(VERS_RESUME) // Function : vers résumé lisible

.forEach([Link]::println); // Consumer

// ■■ Traitement 4 : TVA totale sur commandes


livrées ■■■■■■■■■■

double tvaTotal = [Link]()

.filter(c -> [Link]() == [Link]) // Predicate inline

.mapToDouble(c -> CALC_TVA.apply(c)) // Function → ToDoubleFunction

.sum(); // total TVA

// ■■ Traitement 5 : créer une nouvelle commande


via Supplier ■■

String nouvelId = GEN_ID.get(); // Supplier : générer un ID

Commande nouvCmd = new Commande(nouvelId,


"CLIENT-42",

[Link]("Produit A", "Produit B"),

149.90, Statut.EN_ATTENTE, [Link]());

// Appliquer une remise conditionnelle via


UnaryOperator

if (MONTANT_ELEVE.test(nouvCmd)) { // Predicate : vérifier si > 500€

nouvCmd = APPLIQUER_REMISE.apply(nouvCmd); // UnaryOperator : -10%

Interfaces Fonctionnelles Java — Guide Complet Page 25


POO Java · [Link] · Lambda · Method Reference

9. Tableau Récapitulatif & Bonnes Pratiques

9.1 Tableau récapitulatif complet


Interface Entrée(s) Sortie Méthode Cas d'usage typique

Function<T,R> T R apply(T) Transformer un objet

UnaryOperator<T> T T apply(T) Transformer → même type

BiFunction<T,U,R> T, U R apply(T,U) Combiner deux objets

BinaryOperator<T> T, T T apply(T,T) Combiner deux T en T

Predicate<T> T boolean test(T) Filtrer, valider

BiPredicate<T,U> T, U boolean test(T,U) Tester deux valeurs

Consumer<T> T void accept(T) Effet de bord (log, save)

BiConsumer<T,U> T, U void accept(T,U) Effet de bord ([Link])

Supplier<T> (aucune) T get() Factory, valeur par défaut

Runnable (aucune) void run() Tâche sans argument ni retour

Callable<T> (aucune) T Tâche async avec résultat


call() throws Exception

Comparator<T> T, T int compare(T,T) Trier des éléments

IntFunction<R> int R apply(int) int → objet (sans boxing)

ToIntFunction<T> T int applyAsInt(T) objet → int (sans boxing)

IntUnaryOperator int int applyAsInt(int) int → int (sans boxing)

IntPredicate int boolean test(int) Tester un int (sans boxing)

IntConsumer int void accept(int) Consommer un int

IntSupplier (aucune) int getAsInt() Fournir un int

9.2 Guide de choix rapide

Je veux... Utiliser...

Transformer A en B (types différents) Function<A, B>

Transformer A en A (même type) UnaryOperator<A>

Tester une condition sur A Predicate<A>

Faire une action sur A (sans retour) Consumer<A>

Obtenir un A sans argument Supplier<A>

Combiner A et B pour obtenir C BiFunction<A,B,C>

Combiner deux A pour obtenir un A BinaryOperator<A>

Tester A et B ensemble BiPredicate<A,B>

Interfaces Fonctionnelles Java — Guide Complet Page 26


POO Java · [Link] · Lambda · Method Reference

Faire une action sur A et B BiConsumer<A,B>

Comparer deux A pour les trier Comparator<A>

Transformer sans argument ni retour Runnable

Transformer int → int sans boxing IntUnaryOperator

Transformer objet → int sans boxing ToIntFunction<A>

9.3 Bonnes pratiques

■ Toujours annoter Cela permet au compilateur de vérifier que l'interface a bien une
@FunctionalInterface seule méthode abstraite, et signale l'intention aux développeurs.

■ Préférer les références de String::length est plus lisible que s -> [Link](). Utilisez-les dès
méthodes que la lambda ne fait qu'appeler une méthode.

■ Nommer les lambdas Plutôt qu'une lambda inline de 3 lignes, assignez-la à une variable
complexes nommée (Predicate estValide = ...) pour gagner en lisibilité.

■ Éviter les lambdas avec En stream parallèle, les lambdas doivent être stateless. Ne
effets de bord en parallèle modifiez jamais une variable externe partagée.

■ Utiliser les types primitifs Préférez IntFunction à Function pour les grandes collections afin
pour les perfs d'éviter le boxing/unboxing.

■ Composer plutôt Utilisez andThen, compose, and, or pour combiner des fonctions
qu'imbriquer simples en comportements complexes, plutôt que d'écrire des
lambdas géantes.

Conclusion

Les interfaces fonctionnelles sont le socle du paradigme fonctionnel en Java. Elles permettent de
passer des comportements comme arguments, de composer des fonctions, et d'écrire un code plus
expressif et testable. En maîtrisant les quatre familles fondamentales (Function, Predicate,
Consumer, Supplier) et leurs variantes, vous disposez de tous les outils pour écrire du Java
moderne, qu'il s'agisse de traiter des Streams, de configurer des frameworks ou de modéliser des
règles métier complexes.

Interfaces Fonctionnelles Java — Guide Complet Page 27

Vous aimerez peut-être aussi