Qu'est-ce que null en Java ?
null est une valeur spéciale en Java qui représente l'absence de référence. Elle peut être affectée à n'importe quelle variable de type objet, mais jamais à un type primitif. Bien manipulée, elle exprime l'absence de données ; mal manipulée, elle produit la fameuse NullPointerException.
Définition formelle
En Java, toutes les variables d'un type non primitif (objets, tableaux, interfaces) contiennent soit :
- une référence vers un objet existant dans le tas ;
- la valeur spéciale
null, qui signifie « cette variable ne pointe vers rien ».
String nom = null; // aucune chaîne n'est référencée
User user = null; // aucun utilisateur référencé
int[] scores = null; // aucun tableau référencé
int age = null; // ❌ Erreur : primitif ne peut être null
null n'est pas 0, pas la chaîne vide
| Valeur | Type | Signification |
|---|---|---|
null | Référence | Aucun objet |
"" | String | Chaîne existante, vide |
0 | int | Entier valant zéro |
false | boolean | Booléen faux |
[] (tableau vide) | Array | Tableau existant, de taille 0 |
Une chaîne null n'est pas vide — elle n'existe pas.
NullPointerException
L'erreur survient dès que vous tentez d'utiliser une référence nulle comme un objet :
String nom = null;
int longueur = nom.length(); // ❌ NullPointerException — nom ne pointe sur rien
Depuis Java 14, le message de la NPE pointe précisément quel champ était null (helpful NullPointerException) :
Cannot invoke "String.length()" because "nom" is null
Activé par défaut dans Java 15+.
Tester null correctement
if (nom != null) {
System.out.println(nom.length());
}
// Ou utiliser Objects
if (Objects.isNull(nom)) { ... }
if (Objects.nonNull(nom)) { ... }
Ne jamais utiliser equals() sur une variable qui peut être null :
if (nom.equals("Alice")) { ... } // ❌ NPE si nom == null
// ✅ Inverser l'ordre : la constante ne peut pas être null
if ("Alice".equals(nom)) { ... }
// ✅ Ou utiliser Objects.equals
if (Objects.equals(nom, "Alice")) { ... }
Optional : exprimer l'absence sans null
Depuis Java 8, Optional<T> est une alternative typée. Une méthode qui peut ne pas retourner de valeur le déclare explicitement :
import java.util.Optional;
public Optional<User> findById(long id) {
User u = repository.get(id);
return Optional.ofNullable(u);
}
// Utilisation
findById(42)
.map(User::getName)
.ifPresent(System.out::println);
String nom = findById(42)
.map(User::getName)
.orElse("Inconnu");
Règles d'usage :
- Utilisez
Optionalpour les valeurs de retour qui peuvent être absentes. - Ne l'utilisez pas comme champ d'entité, ni comme paramètre.
- Ne le retournez jamais
null: si la méthode renvoie unOptional, renvoyezOptional.empty().
Annotations @Nullable et @NonNull
Plusieurs bibliothèques (JetBrains, JSR-305, Checker Framework) proposent des annotations que les IDE et outils statiques vérifient :
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public @Nullable String getNom() { return nom; }
public void setEmail(@NotNull String email) {
if (email == null) throw new IllegalArgumentException();
}
IntelliJ vous alerte dès qu'une valeur @Nullable est utilisée sans vérification, ou qu'une variable @NotNull reçoit un null.
Valeurs par défaut pour les champs
Les champs d'objet reçoivent automatiquement des valeurs par défaut :
- Référence (objet, tableau) →
null - Entier (byte/short/int/long) → 0
- Flottant (float/double) → 0.0
- Booléen → false
- char → '\u0000'
Les variables locales, en revanche, n'ont pas de valeur par défaut — il faut les initialiser avant usage, sous peine d'erreur de compilation.
null dans les collections
La plupart des collections acceptent null (ArrayList, HashMap, HashSet) mais pas toutes : Map.of(), List.of() et les concurrent collections rejettent null.
List<String> liste = new ArrayList<>();
liste.add(null); // ✅ autorisé
List<String> immut = List.of("a", null); // ❌ NullPointerException
Bonnes pratiques
- Éviter de retourner
null: préférez une collection vide (List.of()), unOptional, ou lancer une exception. - Valider en entrée : utilisez
Objects.requireNonNull(param, "nom")au début des constructeurs et setters. - Annotations
@Nullable/@NonNull: documentent l'intention et sont vérifiées par les IDE. - Initialiser les champs d'instance plutôt que de compter sur le
nullimplicite. - Préférer
Objects.equalsaux appels directs deequals.
En résumé, null est un outil utile mais glissant. La combinaison Optional + annotations + validation précoce réduit drastiquement les NullPointerException dans un code moderne.