Journal
Progression
Section intitulée « Progression »- Leçon 1 — Le JDK et les outils de build
- Leçon 2 — Types, égalité et opérateurs
- Leçon 3 — Classes, records et enums
- Leçon 4 — Génériques et effacement de type
- Leçon 5 — Exceptions,
nulletOptional - Leçon 6 — Lambdas et interfaces fonctionnelles
- Leçon 7 — Collections et Streams
- Leçon 8 — Pattern matching
- Leçon 9 — Concurrence et threads virtuels
- Leçon 10 — Maven et Gradle en profondeur
- Leçon 11 — Tests
- Leçon 12 — La bibliothèque standard du quotidien
- Leçon 13 — La JVM à l’exécution
- Leçon 14 — Annotations, réflexion et modules
2026-09-13 — Leçons 1 à 4
Section intitulée « 2026-09-13 — Leçons 1 à 4 »- Chaîne d’outils sur ma machine : OpenJDK
25+36, Maven 3.9.16, Gradle 9.7.1, et le SDK .NET 10 pour le côté C#. La CI utilise Eclipse Temurin 25 sous Windows, Ubuntu et macOS. - Le code du cours se trouve dans
code/java-for-csharp:- la sortie de chaque exemple est comparée à la leçon par un test JUnit ;
- chaque extrait rejeté est compilé via l’API
javax.toolset doit produire la clé de diagnostic javac que cite la leçon (par exemplecompiler.err.not.exhaustive) — l’équivalent Java des codesE0xxxde Rust ; - les solutions des exercices sont des tests ;
- un petit programme .NET 10 affiche le côté C# de chaque comparaison.
Surprises en venant de C# :
Integer a = 128, b = 128; a == bvautfalse, mais avec 127 c’esttrue. L’intervalle de cache de −128 à 127 n’est pas un détail d’implémentation : la JLS l’impose.java -jarsur un JAR Maven fraîchement construit échoue avecno main manifest attribute. Rien dansdotnet buildne prépare à un artefact qui ne connaît pas son propre point d’entrée.- Un
enumC# accepte(Size)42; un enum Java ne peut pas contenir une valeur qu’il ne déclare pas. Les enums Java sont bien plus proches d’un ensemble scellé d’objets singletons. - Les messages d’erreur de javac sont parfois indirects : créer une classe interne depuis une méthode statique donne
non-static variable this cannot be referenced from a static context.
Ce que j’ai d’abord mal fait :
- Dans un commentaire de code, j’avais décrit
final varcomme « une variable locale readonly de C# ». C# n’a pas de variables locales readonly. Le commentaire le dit désormais. - Je m’attendais à ce que
javac -XDrawDiagnosticset l’API du compilateur rapportent la même clé de diagnostic. Ce n’est pas toujours le cas : pour un ajout dans uneList<? extends Number>, la ligne de commande rapportecompiler.err.cant.apply.symbolstandis que l’API rapporte la version simplifiéecompiler.err.prob.found.req. Les tests utilisent l’API, les leçons citent donc ce que voit l’API. - Plusieurs leçons montraient d’abord un extrait d’un snippet rejeté à côté d’un message d’erreur dont le numéro de ligne se rapportait au fichier entier. Les leçons montrent désormais le fichier complet.
- Le signe
‰d’un exemple s’affichait�dans la console Windows. L’exemple écrit désormais « per mille ».
Cas pratiques dans mes dépôts
Section intitulée « Cas pratiques dans mes dépôts »Chaque cas applique une leçon à un dépôt public, à un commit figé.
GuitarAlchemist/ga — le build du plugin JetBrains (leçon 1)
Section intitulée « GuitarAlchemist/ga — le build du plugin JetBrains (leçon 1) »jetbrains-plugin/ à ga@5560b883 est un projet Gradle en Kotlin DSL (le plugin lui-même est écrit en Kotlin). Je l’ai copié et j’ai essayé de le compiler sur cette machine.
-
Le wrapper est incomplet. Seul
gradle/wrapper/gradle-wrapper.propertiesest versionné.gradlew,gradlew.batetgradle-wrapper.jarmanquent :./gradlewn’existe donc pas et chaque contributeur doit installer un Gradle compatible.gradle wrapperrégénère les trois fichiers, qu’il faudrait versionner. -
Gradle 8.5 ne peut pas tourner sur JDK 25. Avec le Gradle 8.5 figé et JDK 25,
gradle helpéchoue avec un message d’un seul mot :* What went wrong:25La trace de pile montre une
java.lang.IllegalArgumentException: 25levée pendant que Gradle compile le script de build Kotlin : le compilateur Kotlin embarqué dans cette version de Gradle ne connaît pas Java 25. La correction passe soit par un JDK que Gradle 8.5 prend en charge, soit par un Gradle plus récent ; la matrice de compatibilité de Gradle indique quelle version de Gradle tourne sur quelle version de Java. -
Mettre à jour Gradle seul ne suffit pas. Avec Gradle 9.7.1, le build va plus loin et échoue dans l’ancien plugin
org.jetbrains.intellij1.16.1 :class org.jetbrains.intellij.MemoizedProvider overrides final method org.gradle.api.internal.provider.AbstractMinimalProvider.toString()Ljava/lang/String;Ce plugin a été remplacé par l’IntelliJ Platform Gradle Plugin 2.x, qui utilise un DSL différent. La migration est un vrai changement, pas une simple montée de version.
-
Le dossier de cache de Gradle est versionné. Douze fichiers sous
jetbrains-plugin/.gradle/(fichiers de verrou, sommes de contrôle,last-build.bin) sont dans le dépôt, l’équivalent Gradle de versionnerobj/. Il a sa place dans le.gitignore. -
Une cible Java sans toolchain. Le script définit
sourceCompatibility = "17"sur chaque tâcheJavaCompileau lieu d’un blocjava { toolchain { … } }: le JDK utilisé dépend donc de la machine qui exécute Gradle — exactement la variabilité que décrit la note sur les toolchains de la leçon 1.
Étape suivante, à vérifier : générer le wrapper, migrer vers le plugin 2.x, et vérifier que le plugin se charge toujours dans une version actuelle d’IntelliJ IDEA.
spareilleux/learn — l’exemple Spring Boot du cours WSL (leçon 1, exercice 2)
Section intitulée « spareilleux/learn — l’exemple Spring Boot du cours WSL (leçon 1, exercice 2) »code/wsl-containers/java-reactor-api n’a aucune configuration de maven-jar-plugin, et pourtant java -jar target/app.jar fonctionne. Le compiler montre pourquoi :
Main-Class: org.springframework.boot.loader.launch.JarLauncherStart-Class: dev.learn.reactorapi.JavaReactorApiApplicationLe spring-boot-maven-plugin réempaquette le JAR : la Main-Class du manifeste est le lanceur de Spring Boot, qui lit Start-Class et charge les 62 JAR de dépendances imbriqués sous BOOT-INF/lib/ (35 Mo au total). Il répond aux deux moitiés de l’exercice 2 — le point d’entrée manquant et les dépendances manquantes. L’élément <parent> (spring-boot-starter-parent) explique aussi pourquoi le POM n’indique aucune version de plugin ni de dépendance : il joue le rôle de Directory.Packages.props et des valeurs par défaut du SDK. La leçon 10 y reviendra.
Questions ouvertes
Section intitulée « Questions ouvertes »- Maven 4 vaut-il déjà la peine d’être enseigné, alors que la plupart des projets utilisent encore la 3.9 ? À vérifier : son statut de publication.
- Comment les inspections d’IntelliJ IDEA se comparent-elles à
-Xlint:allde javac pour les pièges des leçons 2 et 3 ?