27 mars 2025

Interfaces fonctionnelles : L'essentiel à savoir

Design & Code

Rania

HELALI

Photo ordinateur.

27 mars 2025

Interfaces fonctionnelles : L'essentiel à savoir

Design & Code

Rania

HELALI

Photo ordinateur.

27 mars 2025

Interfaces fonctionnelles : L'essentiel à savoir

Design & Code

Rania

HELALI

Photo ordinateur.

Ce que vous allez retenir

  • Comprendre les interfaces fonctionnelles
    Vous apprendrez ce qu'est une interface fonctionnelle, comment elle fonctionne et pourquoi elle est essentielle en Java 8.

  • Maîtriser les interfaces prédéfinies
    Découvrez Predicate, Consumer, Supplier, Function et BiFunction pour écrire un code plus concis et lisible.

  • Utiliser les expressions lambda & références de méthodes
    Apprenez à simplifier votre code en remplaçant les classes anonymes par des lambdas et des références de méthodes.

Cela fait un moment, mais Java 8 a apporté de nombreuses fonctionnalités intéressantes. L'une des plus révolutionnaires a été l'introduction des interfaces fonctionnelles. Si vous avez déjà été noyé sous les classes anonymes, les interfaces fonctionnelles sont là pour vous sauver ! Alors, plongeons dedans, amusons-nous et apprenons l'essentiel sur les interfaces fonctionnelles en Java 8.

Qu'est-ce qu'une Interface Fonctionnelle ?

Une interface fonctionnelle est une interface qui possède exactement une seule méthode abstraite. Imaginez-la comme cet ami minimaliste qui n'a besoin que d'une seule chose pour fonctionner correctement. Bien sûr, elle peut contenir plusieurs méthodes par défaut ou statiques, mais une seule méthode abstraite définit son comportement fonctionnel.

L'Annotation @FunctionalInterface

Java fournit l'annotation @FunctionalInterface pour garantir qu'une interface est bien fonctionnelle. Si vous ajoutez accidentellement une autre méthode abstraite, le compilateur renverra une erreur. Cette annotation est facultative mais recommandée, car elle indique clairement au compilateur :
"Hey, cette interface est censée être fonctionnelle !"

Exemple :

@FunctionalInterface
interface Greeting {
    void sayHello();
}

Une seule méthode—clair et simple !

Pourquoi est-ce important ?

Parce que les interfaces fonctionnelles permettent d'utiliser les expressions lambda, et les expressions lambda rendent votre code plus concis et lisible ! Sans elles, vous seriez coincé avec des classes internes anonymes, comme si vous étiez encore en 2005...

Avant Java 8 (L'Âge Sombre)

Si vous vouliez passer un comportement en argument, vous deviez créer une classe anonyme:

Greeting greeting = new Greeting() {
  @override 1 usage
  public voide sayHello(String name) {
    System.out.println("Hello, "+name+"!");
  }
};

greeting.sayHello(name: "Alice");

 

Interfaces Fonctionnelles Prédéfinies en Java 8

Java propose dans le package java.util.function des interfaces fonctionnelles prêtes à l'emploi.

Voici les plus courantes :

1. Predicate<T> – Vérifie une Condition

Utilisé pour tester si une condition est vraie ou fausse.

import java.util.function.Predicate;

public class PredicateExample {
    public static void main(String[] args) {
        Predicate<Integer> isEven = num -> num % 2 == 0;
        System.out.println(isEven.test(10)); // true
        System.out.println(isEven.test(11)); // false
    }
}

2. Consumer<T> – Consomme une Valeur sans Retour

Prend une entrée et exécute une action, mais ne retourne rien.

import java.util.function.Consumer;

public class ConsumerExample {
    public static void main(String[] args) {
        Consumer<String> printMessage = message -> System.out.println("Message: " + message);
        printMessage.accept("Hello, Java 8!");
    }
}

3. Supplier<T> – Fournit une Valeur

Fournit une valeur à la demande, comme une machine à café, mais sans le stress existentiel.

import java.util.function.Supplier;

public class SupplierExample {
    public static void main(String[] args) {
        Supplier<Double> randomValue = () -> Math.random();
        System.out.println(randomValue.get());
    }
}

4. Function<T, R> – Transforme une Valeur

Prend une entrée et retourne une autre valeur (comme transformer un code en bugs en production… Juste une blague, enfin j’espère).

import java.util.function.Function;

public class FunctionExample {
    public static void main(String[] args) {
        Function<String, Integer> stringLength = str -> str.length();
        System.out.println(stringLength.apply("Functional Interface")); // 19
    }
}

 5. BiFunction<T, U, R> – Prend Deux Arguments et Retourne un Résultat

Parfois, un seul paramètre ne suffit pas. Utilisez BiFunction !

import java.util.function.BiFunction;

public class BiFunctionExample {
    public static void main(String[] args) {
        BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
        System.out.println(add.apply(5, 10)); // 15
    }
}

 Créer ses Propres Interfaces Fonctionnelles

Si les interfaces prédéfinies ne suffisent pas, vous pouvez toujours créer la vôtre.

@FunctionalInterface
interface MathOperation {
    int operate(int a, int b);
}

public class CustomFunctionalInterfaceExample {
    public static void main(String[] args) {
        MathOperation addition = (a, b) -> a + b;

        System.out.println(addition.operate(10, 5)); // 15
    }
}

Références de Méthodes – Un Raccourci pour les Lambdas

Au lieu d'écrire une expression lambda complète, utilisez une référence de méthode.

import java.util.function.Consumer;

public class MethodReferenceExample {
    public static void main(String[] args) {
        Consumer<String> print = System.out::println;
        print.accept("Hello, method references!");
    }
}

Coder comme un pro du fonctionnel : Adopter la programmation fonctionnelle en Java

Très bien, maintenant que vous êtes à l’aise avec les interfaces fonctionnelles, les lambdas et les références de méthode, passons au niveau supérieur. 🚀

L'approche fonctionnelle vs. l'approche traditionnelle

Dans le monde classique de la programmation orientée objet, nous écrivions une méthode pour filtrer les nombres pairs comme ceci :

import java.util.ArrayList;
import java.util.List;

class NumberFilter {
    static List<Integer> filterEvenNumbers(List<Integer> numbers) {
        List<Integer> result = new ArrayList<>();
        for (Integer num : numbers) {
            if (num % 2 == 0) {
                result.add(num);
            }
        }
        return result;
    }
}


Cela fonctionne, mais c'est verbeux, procédural et donne l'impression de microgérer l'ordinateur au lieu de le laisser faire son travail.

Passons maintenant à une approche fonctionnelle ! 🎸

@FunctionalInterface
interface Condition<T> {
    boolean test(T t);
}

Maintenant, au lieu de coder la logique en dur dans une méthode, rendons-la plus flexible :

import java.util.List;

class NumberFilter{
    static List<Integer> filter(List<Integer> numbers, Condition<Integer> condition) {
        return numbers.stream()
                .filter(condition::test)
                .toList();
    }
}


Cette méthode peut désormais filtrer n'importe quoi en fonction de la condition que nous lui passons. 🎉

L'utiliser comme un pro

Au lieu d'écrire toute une classe pour filtrer les nombres pairs, il suffit de passer une lambda :

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // Using a lambda expression
        List<Integer> evens = NumberFilter.filter(numbers, n -> n % 2 == 0);

        System.out.println("Even numbers: " + evens); // [2, 4, 6, 8, 10]
    }
}

🔥 Boom ! Vous venez d'écrire du code Java propre, réutilisable et fonctionnel, sans code inutile !

Aller encore plus loin : les références de méthode

Si vous avez déjà une méthode qui vérifie si un nombre est pair, vous pouvez vous passer totalement de la lambda :

import java.util.List;

class MathUtils {
    static boolean isEven(Integer n) {
        return n % 2 == 0;
    }
}

class Main {
    public static void main(String[] args) {
        List<Integer> evens = NumberFilterFunctional.filter(List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), MathUtils::isEven);

        System.out.println("Even numbers: " + evens);
    }
}

En résumé

Les interfaces fonctionnelles en Java 8 rendent votre code plus propre, plus lisible et moins verbeux. Que vous filtriez des listes, transformiez des données ou réduisiez simplement le code répétitif, elles apportent une nouvelle façon d’écrire du Java. Et franchement, qui n’aime pas taper moins de code ?

Maintenant que vous connaissez l’essentiel (mais le plus important) sur les interfaces fonctionnelles, lancez-vous et adoptez le côté fonctionnel de Java !