0Pricing
Java Academy · Leçon

Bonnes pratiques avec Optional

Appliquez orElse, orElseGet et orElseThrow, et évitez les anti-modèles courants liés à Optional.

Bonnes pratiques avec Optional est une leçon Java Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Java Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Java Academy comprend 4 leçons au total.

Bonnes pratiques pour Optional

Optional est un outil puissant lorsqu’il est utilisé correctement. Cette leçon présente les bonnes et les mauvaises pratiques à l’aide d’exemples concrets issus de bases de code réelles.

À faire : utiliser Optional comme type de retour

Le principal cas d’utilisation d’Optional est le type de retour des méthodes qui peuvent ne pas trouver ou produire de valeur.

import java.util.Optional;

// Good: signals to caller that result might be absent
public Optional<User> findByUsername(String username) { ... }
public Optional<Config> getConfig(String key) { ... }
public Optional<String> getHeader(String name) { ... }

// These are all cases where absence is a normal outcome,
// not an exceptional condition

À éviter : Optional comme champ

Les champs de type Optional ajoutent une surcharge aux objets et compliquent la sérialisation. Utilisez une absence ou une valeur sentinelle pour les champs facultatifs à l’intérieur des classes.

// BAD
class User {
    private Optional<String> middleName; // wrong
}

// GOOD: use null for absent optional field
class User {
    private final String middleName; // null = absent
    public Optional<String> middleName() {
        return Optional.ofNullable(middleName); // expose as Optional in getter
    }
}
User u = new User(null); // null field
System.out.println(u.middleName().isPresent()); // false

À éviter : Optional comme paramètre de méthode

Les paramètres Optional obligent inutilement les appelants à encapsuler les valeurs dans un Optional. Utilisez la surcharge ou @Nullable à la place.

// BAD
void sendNotification(String message, Optional<String> subject) { ... }
// caller must write: sendNotification("Hello", Optional.of("News"))

// GOOD: overloading
void sendNotification(String message) { sendNotification(message, null); }
void sendNotification(String message, String subject) {
    // subject may be null
}
// caller writes: sendNotification("Hello", "News") — clean

À éviter : Optional dans les collections

Ne placez jamais d’Optional dans une List, un Set ou la valeur d’une Map. Les Optional vides dans les collections n’ont aucun sens : omettez simplement l’entrée.

// BAD: List of Optionals
List<Optional<User>> results = ...; // meaningless empty Optionals

// GOOD: List of present values only
List<User> presentUsers = maybeUsers.stream()
    .flatMap(Optional::stream)
    .collect(Collectors.toList());

// BAD: Map with Optional values
Map<String, Optional<String>> config = ...;

// GOOD: just use null or omit the key for absent values
Map<String, String> config2 = ...;
String value = config2.getOrDefault("key", "default");

À faire : orElseGet pour les valeurs par défaut coûteuses

Lorsque la valeur par défaut nécessite un calcul (requête de base de données, appel réseau), utilisez toujours orElseGet : le fournisseur n’est appelé qu’en cas de besoin.

import java.util.Optional;

// BAD: buildDefault() always called, even when value is present!
String config = getConfig("timeout").orElse(buildDefault());

// GOOD: supplier called lazily only when empty
String config2 = getConfig("timeout").orElseGet(() -> buildDefault());

// Or with method reference:
String config3 = getConfig("timeout").orElseGet(this::buildDefault);

// For cheap literals, orElse is fine
String name = getConfig("name").orElse("default");

À faire : orElseThrow pour les valeurs requises

Lorsqu’une valeur absente signale une erreur de programmation ou une violation d’invariant, utilisez orElseThrow avec une exception descriptive.

import java.util.Optional;

// Good: throw when absence is an error
User user = userRepository.findById(userId)
    .orElseThrow(() -> new UserNotFoundException("User not found: " + userId));

// Good: in validation code
String apiKey = Optional.ofNullable(System.getenv("API_KEY"))
    .orElseThrow(() -> new IllegalStateException(
        "API_KEY environment variable is required"));

System.out.println("Key found: " + apiKey.length() + " chars");

Anti-modèle : isPresent + get()

Évitez l’anti-modèle qui consiste à vérifier isPresent(), puis à appeler get(). Cette approche ne vaut pas mieux qu’une vérification d’absence et va à l’encontre de l’objectif d’Optional.

import java.util.Optional;

Optional<String> opt = findValue();

// BAD: isPresent() + get() — no improvement over null check
if (opt.isPresent()) {
    String val = opt.get();
    process(val);
}

// GOOD: use the functional API
opt.ifPresent(this::process);

// GOOD: transform and return
return opt.map(this::process).orElse(null);

// GOOD: provide a default
String result = opt.orElse("default");

Bonne pratique pour les chaînes

Construisez une chaîne claire : find → filter → transform → fallback. Chaque étape explique elle-même son rôle.

import java.util.Optional;

record User(long id, String plan, boolean active) {}

static Optional<User> findUser(long id) { return Optional.empty(); }

String result = findUser(42L)
    .filter(User::active)           // keep only active users
    .filter(u -> "PRO".equals(u.plan())) // keep only PRO users
    .map(u -> "Welcome, Pro user #" + u.id()) // transform
    .orElse("Upgrade to Pro!");     // fallback

System.out.println(result); // Upgrade to Pro!

Optional dans la couche de service

Exemple réaliste de couche de service appliquant les bonnes pratiques.

import java.util.Optional;

class OrderService {
    public Optional<OrderSummary> getOrderSummary(long orderId) {
        return orderRepo.findById(orderId)
            .filter(o -> !o.isCancelled())
            .map(this::toSummary);
    }

    public OrderSummary requireOrderSummary(long orderId) {
        return getOrderSummary(orderId)
            .orElseThrow(() -> new OrderNotFoundException(orderId));
    }

    private OrderSummary toSummary(Order o) { return new OrderSummary(o); }
}
// API callers choose: Optional (handle absence) or require (exception)

Optional et les outils de sécurité vis-à-vis des absences

Optional complète les annotations @Nullable/@NonNull et des outils comme SpotBugs/NullAway pour assurer une couverture complète de la sécurité vis-à-vis des absences.

// Annotation-based: declares intent for in-class nulls
import org.jetbrains.annotations.*;

class ProductService {
    @Nullable  // may return null — for framework/bean use
    public String getCachedName(String id) { return cache.get(id); }

    // Optional — for service API that handles absence
    public Optional<Product> findProduct(String id) {
        return repo.findById(id);
    }
}
// Use @Nullable for fields/parameters; Optional for return types

Vérification rapide

Quel est le problème du code suivant ?

if (opt.isPresent()) {
    process(opt.get());
}

Récapitulatif : bonnes pratiques pour Optional

Points essentiels :

  • Utilisez Optional uniquement comme type de retour, jamais comme champ ou paramètre de méthode
  • Préférez orElseGet à orElse lorsque la valeur par défaut est coûteuse à calculer
  • Utilisez orElseThrow lorsque l’absence représente une erreur de programmation
  • Évitez isPresent() + get() : utilisez plutôt ifPresent, map ou orElse
  • Ne placez jamais Optional dans des collections : filtrez plutôt les flux
  • Construisez des chaînes lisibles : filter → map → orElse pour représenter clairement le flux de données

Questions Fréquemment Posées

La leçon « Bonnes pratiques avec Optional » est-elle gratuite ?

Oui — le texte complet de « Bonnes pratiques avec Optional » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Java Academy, passe à CoddyKit PRO. Le cours Java Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Bonnes pratiques avec Optional » ?

Appliquez orElse, orElseGet et orElseThrow, et évitez les anti-modèles courants liés à Optional. Tu pratiques Java Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Java Academy ?

Aucune expérience préalable n'est requise. Java Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.

Combien de temps prend la leçon « Bonnes pratiques avec Optional » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Java Academy ?

Oui. Chaque leçon Java Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Pourquoi Optional existe
  2. Créer et inspecter des Optional
  3. Transformer des Optional : map et flatMap
  4. Bonnes pratiques avec Optional
← Retour à Java Academy