Coupe du monde 2026, un but litigieux. L'arbitre s'arrête, va vérifier une image que personne dans le stade ne voit, puis revient donner sa décision. Elle est peut-être juste. Mais personne dans le stade n'a vu ce qu'il a vu.
Je retrouve exactement ce mécanisme en revue de code, sur une ligne aussi anodine que celle-ci :
var result = orderService.process(command);
result de quel type ? Aucune idée, sauf à aller chercher la signature de process(). L'information existe quelque part, hors champ. Exactement comme la VAR : la vérité est disponible mais pas à l'endroit où je la regarde.
Précisons tout de suite le périmètre, parce que le débat sur var part souvent dans le décor : le type n'est jamais perdu. Le compilateur le connaît, un LSP le connaît, l'IDE le connaît (la même vérité se niche jusque dans le bytecode que la JVM manipule). On ne parle donc pas d'un bug ni d'une perte d'information : javac refuserait de compiler une erreur de type. On parle d'un surcoût de lecture : le prix à payer, en attention, pour reconstituer une information que la ligne aurait pu porter d'elle-même.
Quand var ne me pose aucun problème
La moitié des débats sur var sont, à mon sens, mal posés. Quand le type est déjà écrit à droite du =, var ne masque rien du tout :
var users = new ArrayList<User>();
var client = HttpClient.newHttpClient();
Ici, personne ne perd d'information. var retire juste une redondance visuelle. C'est le cas d'usage que tout le monde cite pour défendre var, et il est parfaitement légitime. Je l'utilise sans hésiter.
var n'est pas seul en cause : le nom l'est aussi
Avant d'accuser var, une objection que je me fais à moi-même. Reprenons la ligne du début :
var result = orderService.process(command);
Ce qui me gêne ici, ce n'est pas seulement var : c'est que result ne veut rien dire. L'école pro-var (dont Brian Goetz, architecte du langage) tient d'ailleurs cet argument : quand le type quitte la ligne, le nom de la variable doit prendre le relais.
var confirmedOrder = orderService.process(command);
D'un coup, la ligne se lit seule. var a même un effet que j'apprécie : il met une pression sur le nommage que OrderResult result = ... relâche, parce que le type « fait déjà le travail ». Une partie de ce que je reprochais à var est donc, en réalité, un défaut de nommage.
Mais cette défense a une limite. Un bon nom porte l'intention de la variable (« la commande confirmée »), pas sa forme technique. Est-ce un Order, un Optional<Order>, un CompletableFuture<Order> ? Le nom ne le dira jamais complètement et c'est précisément cette forme dont j'ai besoin pour lire la ligne suivante.
Quand var ment par omission
Le problème commence donc dès que, ni l'expression, ni le nom ne suffisent :
var items = repository.findActive();
var config = builder.withDefaults().build();
Est-ce que items est une List, un Stream, un Set trié ou pas ? Est-ce que config est déjà build() ou encore un builder ? Rien dans la ligne ne le dit. Le type existe, il est juste devenu invisible à l'endroit précis où j'en ai besoin et aucun nom, aussi soigné soit-il, ne rattrape totalement cette forme-là.
Le vrai terrain du problème : hors IDE
Voilà l'argument que j'entends le moins souvent et c'est pourtant celui qui me convainc le plus : dans l'IDE, ce débat n'a presque pas lieu d'être. Je survole items, IntelliJ ou VS Code me donne le type en une frappe. Le problème n'est donc pas « var masque le type », il est « var masque le type dès qu'on sort du contexte outillé qui sait l'inférer ».

Et je sors de ce contexte plus souvent que je ne le crois :
- une revue de code sur GitHub, où je lis un diff, pas un projet ouvert dans un IDE ;
- un
git log -pou ungit blamedans un terminal ; - un extrait de code collé dans un ticket, un Slack, une doc ;
- un extrait donné à un assistant IA sans accès au reste du projet.
Dans chacun de ces cas, var transforme une lecture triviale en enquête. Je rejoue la VAR : la décision est disponible, ailleurs, pour qui prend la peine d'aller la chercher.
L'IA : à condition de ne pas se tromper de LLM
C'est l'argument qu'on brandit le plus vite en 2026 et c'est aussi celui que je manie avec le plus de précaution. Il faut distinguer deux situations que je vois souvent confondues.
Un assistant IA correctement outillé n'a aucun problème avec var. Branché sur le projet via un LSP, un serveur MCP ou simplement un accès au dépôt, il fait exactement ce que fait mon IDE : il remonte à la signature de process() et connaît le type. Mieux : s'il se trompe et propose un refactoring incohérent, javac le rattrape à la compilation. Sur ce terrain, var n'est pas un problème et prétendre le contraire, ce serait dater l'article avant même sa publication.
Le problème est ailleurs : le LLM aveugle. Un snippet collé dans un prompt, un contexte tronqué par la fenêtre, un pipeline qui ne transmet qu'un diff. Là, l'assistant n'a ni survol ni compilateur : il doit deviner le type de items à partir du nom et des usages. Il devine souvent bien, parfois faux, et cette fois sans filet, puisque le code ne sera pas recompilé dans ce contexte. Le risque n'est pas un bug en prod (le compilateur veille, quand il tourne), c'est du bruit : une explication approximative, une suggestion à côté, une revue automatique qui passe à côté de l'essentiel.
Le paradoxe tient, à condition de le formuler juste : je multiplie les points de la chaîne où le code est lu hors de son contexte outillé, et c'est là, et seulement là, que var fait payer son omission.
En pratique
Sur mes projets Java, je ne bannis pas var, je lui applique une règle simple : var améliore-t-il la lisibilité ou déporte-t-il une information qu'aucun nom ne rattrapera hors IDE ?
J'utilise var sans réserve quand :
- le type est déjà écrit à droite du
=:var users = new ArrayList<User>();; - c'est une variable de boucle :
for (var order : orders); - le type est imprononçable : résultat d'un
Stream.collect, classe anonyme, type intersection, qu'on ne peut parfois même pas écrire à la main ; - le type est pénible à recopier : un générique monstrueux où
var index = ...vaut clairement mieux queMap<String, List<OrderLine>> index = ...répété à l'identique.
J'explicite le type quand la ligne perd sa forme technique sans qu'un bon nom la remplace : typiquement un appel de méthode dont le retour n'est pas évident (Optional, Stream, Either…).
C'est exactement la ligne que pose le guide de style officiel d'OpenJDK sur l'inférence de type : utiliser var quand il aide à lire, pas par principe. Je m'appuie dessus en revue quand la discussion s'enlise, ça évite les débats de principe.
Conclusion
La VAR au foot devait rendre les décisions plus claires. Elle a surtout déplacé le doute : on ne discute plus l'action, on discute ce que l'arbitre a vu ou pas vu, ailleurs, hors de notre regard. var en Java fait quelque chose de comparable avec les types : il ne les supprime pas (le compilateur les tient toujours), il les déplace hors de la ligne, là où seul un outil peut aller les rechercher.
var n'est pas un défaut. C'est un pari sur le fait que le lecteur aura toujours le bon outil sous la main. Le type n'est pas perdu, il est déplacé : var déporte la forme hors de la ligne, le compilateur la connaît toujours, moi pas, sans outil. Et ce coût se paie hors IDE, dans un diff, un terminal, un snippet sans contexte, y compris pour un LLM aveugle. D'où ma règle : utiliser var lorsqu'il clarifie la lecture, et expliciter le type dès qu'aucun nom de variable ne suffit à compenser la perte de contexte.