Optional en Java pour éviter les pièges de null

Alfred Jacques .

25 octobre 2026

Extrait de code Java montrant l'utilisation de `Optional` pour gérer les valeurs potentiellement nulles. Il vérifie si une valeur est présente et utilise `orElse` pour fournir une valeur par défaut.

Une méthode qui peut ne rien trouver ne devrait pas laisser un null se promener discrètement dans toute l’application. En Java, la classe Optional rend cette absence explicite et aide à construire des traitements plus sûrs, notamment dans les services web, les accès aux bases de données et les API. Je vous montre comment la créer, la lire, la transformer et surtout quand éviter de l’utiliser.

L’essentiel pour utiliser Optional sans alourdir votre code

  • Optional représente une valeur présente ou absente.
  • ofNullable() convient lorsqu’une source peut déjà renvoyer null.
  • orElseGet() évite de calculer inutilement une valeur par défaut.
  • map() transforme une valeur, tandis que flatMap() évite les Optional imbriqués.
  • get() est rarement un bon choix, car il peut lever une exception.

Comparaison des types non nullables et nullables en Java. Les types nullables peuvent être `null`, contrairement aux autres.

Comprendre ce que représente Optional en Java

Optional est un conteneur qui peut contenir une valeur non nulle ou être vide. Il ne remplace pas tous les usages de null, mais il permet à une méthode d’indiquer clairement qu’un résultat peut être absent. Pour moi, c’est surtout un contrat lisible entre une méthode et son appelant.

Une méthode comme findById() ne promet pas de trouver un utilisateur. Avec Optional, cette possibilité devient visible dans sa signature, ce qui pousse le développeur à traiter les deux cas au lieu de supposer que la valeur existe toujours.

public Optional trouverParId(long id) {
    // résultat présent ou Optional.empty()
}

La classe est apparue avec Java 8 et se trouve dans le package java.util. La documentation Java la destine principalement aux valeurs de retour lorsqu’un résultat peut manquer, et non au stockage systématique dans les champs ou aux paramètres de méthode.

Créer un Optional correctement

Quand la valeur est obligatoirement présente

Optional.of() convient lorsque vous êtes certain que la valeur n’est pas nulle. Si cette hypothèse est fausse, Java lève immédiatement une NullPointerException. Ce comportement est utile pour détecter une incohérence tôt, mais il ne faut pas l’utiliser avec une donnée provenant d’une base ou d’une requête utilisateur sans vérification.

Optional nom = Optional.of("Camille");

Quand la valeur peut être nulle

Optional.ofNullable() convertit une valeur existante en conteneur rempli, ou crée un conteneur vide si la valeur vaut null. C’est généralement le bon choix pour adapter une ancienne API, un résultat JDBC ou une propriété dont la présence n’est pas garantie.

String valeur = lireDepuisUneSource();
Optional resultat = Optional.ofNullable(valeur);

Représenter explicitement l’absence

Pour renvoyer une absence, utilisez Optional.empty(). Je préfère cette forme à un null retourné par une méthode, car l’appelant sait immédiatement quelle stratégie appliquer et le risque d’un oubli diminue fortement.

return Optional.empty();

Une règle simple évite beaucoup de problèmes. Ne retournez jamais null à la place d’un Optional, et n’écrivez pas Optional.of(null). Si la donnée peut manquer, utilisez ofNullable() ou empty().

Lire la valeur sans recréer les pièges de null

La méthode isPresent() indique si une valeur existe, tandis que isEmpty(), disponible depuis Java 11, teste l’absence. Ces méthodes sont utiles dans certains cas, mais un enchaînement de conditions qui ressemble à l’ancien code avec null perd une partie de l’intérêt d’Optional.

if (utilisateur.isPresent()) {
    envoyerEmail(utilisateur.get());
}

Dans ce cas, ifPresent() est souvent plus expressif. L’action ne s’exécute que si la valeur est là, sans appel direct à get().

utilisateur.ifPresent(this::envoyerEmail);

Lorsque les deux branches doivent être traitées, ifPresentOrElse() permet de conserver une logique claire. Cette méthode est particulièrement pratique pour journaliser l’absence d’une ressource ou renvoyer une réponse adaptée dans un contrôleur.

utilisateur.ifPresentOrElse(
    this::afficherProfil,
    () -> afficherMessage("Utilisateur introuvable")
);

Lire aussi : À quoi sert Java ? Usages réels et pertinence en 2026

Choisir une valeur de remplacement

orElse() renvoie la valeur contenue ou une valeur de secours. Attention, son argument est évalué immédiatement, même lorsque l’Optional contient déjà une valeur. Si le remplacement déclenche un appel réseau, une requête SQL ou un calcul coûteux, cette différence peut devenir mesurable.

String nom = utilisateur
    .map(Utilisateur::getNom)
    .orElse("Visiteur");

orElseGet() reçoit un fournisseur exécuté uniquement si l’Optional est vide. Dans mon code, c’est celui que je choisis dès que la valeur par défaut n’est pas purement littérale ou qu’elle demande un traitement.

Utilisateur resultat = utilisateur.orElseGet(this::creerUtilisateurInvite);

Enfin, orElseThrow() ou sa version avec fournisseur d’exception convient lorsque l’absence représente une erreur métier. Cette approche transforme une absence silencieuse en décision explicite, avec une exception adaptée au contexte.

Utilisateur resultat = utilisateur.orElseThrow(
    () -> new UtilisateurIntrouvableException(id)
);

Transformer et enchaîner les traitements

L’un des vrais avantages de cette API apparaît lorsque plusieurs étapes peuvent échouer. map() applique une fonction uniquement si la valeur existe et encapsule le résultat dans un nouvel Optional. Si la fonction renvoie null, le résultat devient vide au lieu de propager un nouveau null.

Optional email = utilisateur
    .map(Utilisateur::getProfil)
    .map(Profil::getEmail);

Quand la fonction appelée renvoie déjà un Optional, utilisez flatMap(). Avec map(), vous obtiendriez un type imbriqué comme Optional>. flatMap() aplati cette structure et garde une chaîne de traitement lisible.

Optional adresse = utilisateur.flatMap(Utilisateur::getAdresse);

filter() permet de conserver la valeur uniquement si elle respecte une condition. C’est pratique pour exprimer une règle courte, par exemple vérifier qu’un compte est actif avant de poursuivre.

Optional actif = utilisateur
    .filter(Utilisateur::estActif);

Avec les streams, Optional.stream() permet aussi de transformer un résultat facultatif en flux de zéro ou une valeur. Je l’utilise surtout lorsqu’une liste de résultats optionnels doit être aplatie avant un traitement collectif.

List utilisateurs = resultats.stream()
    .flatMap(Optional::stream)
    .toList();

Comparer Optional aux autres façons de gérer l’absence

Optional n’est pas automatiquement meilleur que toutes les alternatives. Le bon choix dépend de la nature de l’absence, de la fréquence du traitement et de la frontière entre votre code et une bibliothèque externe.

Approche Point fort Limite principale
null Simple et sans objet supplémentaire Le contrat est implicite et les erreurs arrivent souvent plus tard
Optional L’absence est visible dans le type de retour Inadapté comme champ permanent ou paramètre omniprésent
Exception Appropriée lorsqu’il s’agit d’une erreur exceptionnelle Trop lourde pour une absence normale et prévisible
Valeur par défaut Le code appelant reste très simple Peut masquer une information importante ou produire une valeur trompeuse

Pour une recherche qui peut légitimement ne rien retourner, je recommande Optional. Pour une violation de règle, une exception métier est plus honnête. Une liste vide reste souvent préférable à Optional>, car elle exprime directement qu’il n’y a aucun élément à parcourir.

Pour les types primitifs, Java propose OptionalInt, OptionalLong et OptionalDouble. Ils évitent l’emballage systématique d’un int, d’un long ou d’un double, mais leur API est un peu différente. Je les réserve aux cas où la performance ou la nature primitive de la donnée compte réellement.

Éviter les usages qui rendent le code plus compliqué

Le premier piège est de transformer chaque variable en Optional. Un champ Optional peut compliquer la sérialisation, les frameworks et les tests sans apporter de bénéfice clair. Dans la majorité des modèles de données, je préfère un champ classique et je réserve Optional aux méthodes qui annoncent un résultat incertain.

Le deuxième piège consiste à appeler get() juste après isPresent() partout. Ce code n’est pas toujours faux, mais il recrée une logique impérative plus difficile à composer. Utilisez plutôt map(), filter(), orElseGet() ou orElseThrow() selon l’intention.

// Fragile lorsque le contrat évolue
String nom = utilisateur.get().getNom();

// Plus explicite
String nom = utilisateur
    .map(Utilisateur::getNom)
    .orElse("Visiteur");

Évitez également les Optional imbriqués et les chaînes interminables de quinze appels. Une chaîne courte rend le parcours des données agréable, tandis qu’un bloc excessivement fonctionnel devient parfois moins lisible qu’une condition classique. La lisibilité reste le critère décisif, surtout dans un service maintenu par plusieurs équipes.

Enfin, ne retournez pas un Optional depuis une méthode qui peut elle-même renvoyer null. Les fonctions passées à flatMap() doivent retourner un Optional non nul, sinon l’erreur réapparaît sous une autre forme. La sécurité vient du contrat appliqué avec rigueur, pas du nom de la classe.

Adopter une règle simple dans vos projets Java

Je conseille de commencer par les méthodes de recherche, comme findById(), findByEmail() ou une résolution de configuration facultative. Faites apparaître l’absence dans le type de retour, puis choisissez à l’appel le comportement adapté, qu’il s’agisse d’une valeur de secours, d’une réponse HTTP 404 ou d’une exception métier.

Gardez en tête cette ligne directrice. Optional décrit une absence attendue, tandis qu’une exception signale une situation anormale. Utilisé à cette frontière, il rend les API plus honnêtes, limite les erreurs liées à null et laisse le code Java suffisamment direct pour rester agréable à maintenir.

Questions fréquentes

Optional convient surtout aux méthodes de recherche dont le résultat peut légitimement manquer, comme findById() ou findByEmail(). Il rend cette possibilité visible dans le type de retour et oblige l’appelant à choisir un comportement adapté.
of() s’utilise uniquement avec une valeur obligatoirement non nulle et lève une NullPointerException si ce n’est pas le cas. ofNullable() transforme une valeur éventuellement nulle en Optional rempli ou vide, tandis que empty() représente directement l’absence.
orElse() évalue immédiatement sa valeur de remplacement, même si l’Optional contient déjà une valeur. orElseGet() n’exécute son fournisseur que lorsque l’Optional est vide, ce qui est préférable pour un calcul coûteux, une requête SQL ou un appel réseau.
map() transforme une valeur présente et encapsule le résultat dans un nouvel Optional. Si la fonction appelée renvoie déjà un Optional, flatMap() évite d’obtenir un type imbriqué comme Optional>.
Évaluer l'article

Moyenne: 0.0 / 5 · 0 évaluations

Tags

optional null streams exceptions
Autor Alfred Jacques
Alfred Jacques
Je m'appelle Alfred Jacques et j'ai accumulé 12 ans d'expérience dans le domaine des technologies, en particulier dans les secteurs du web, de l'intelligence artificielle, des réseaux et de la sécurité. Mon intérêt pour ces sujets a débuté dès mon adolescence, lorsque j'ai découvert les possibilités infinies qu'offrent les nouvelles technologies. J'aime explorer les enjeux complexes de ces domaines et partager des informations claires et accessibles pour aider mes lecteurs à mieux comprendre les défis et les évolutions technologiques. Dans mes écrits, je m'efforce de fournir des analyses précises et à jour, en vérifiant mes sources et en comparant différentes perspectives. Je m'engage à simplifier des concepts parfois difficiles afin de rendre l'information utile et compréhensible pour tous. Que ce soit en suivant les dernières tendances ou en organisant mes connaissances de manière claire, je souhaite que mes articles soient une ressource précieuse pour ceux qui s'intéressent à la technologie et à ses implications dans notre quotidien.
Commentaires (0)
Ajouter un commentaire