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