Installer et lancer¶
On installe le JDK 25, puis on voit toutes les façons d'exécuter du Java : d'un simple fichier jusqu'à la compilation à la main, sans oublier la console interactive.
Dans ce chapitre
- JDK, JRE, distributions : quoi installer et comment (SDKMAN, paquets, archive)
- Lancer un fichier directement avec
java Hello.java - Les deux formes de
main: compacte (Java 25) et classique (celle de Spring) - Compiler à la main avec
javacet lancer avecjava -cp jshell, la console interactive, et le choix d'un IDE
JDK, JRE et distributions¶
- Le JRE (Java Runtime Environment) contient la JVM et la bibliothèque standard : de quoi exécuter du Java.
- Le JDK (Java Development Kit) contient le JRE plus les outils :
javac(compilateur),jshell,javap(désassembleur),jar,javadoc,jlink...
Pour développer, installe toujours un JDK. Le JRE seul ne sert plus qu'à alléger une image Docker (voir Déployer).
Le code source de Java s'appelle OpenJDK. Plusieurs organisations le compilent et le distribuent : Eclipse Temurin (Adoptium), Oracle, Amazon Corretto, Azul Zulu, Microsoft... Elles sont quasi identiques ; ce cours utilise Temurin, gratuite et neutre.
Le rythme des versions
Une nouvelle version de Java sort tous les six mois (mars et septembre). Une version sur quatre est LTS (Long Term Support), maintenue pendant des années : 17, 21, puis 25 (septembre 2025). En entreprise, on reste sur une LTS ; c'est ce que fait ce cours.
Installer le JDK 25¶
Avec SDKMAN (recommandé)¶
SDKMAN est l'équivalent de rustup ou pyenv pour l'écosystème Java : il installe plusieurs JDK côte à côte et bascule entre eux. Il gère aussi Maven et Gradle.
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk list java | grep tem # versions Temurin disponibles
sdk install java 25.0.4.1+1-tem # installe et propose d'en faire la version par défaut
sdk use java 21.0.12+1.1-tem # change de version pour ce terminal seulement
sdk default java 25.0.4.1+1-tem # version par défaut pour tous les terminaux
Les identifiants exacts changent à chaque mise à jour : prends ceux qu'affiche sdk list java. SDKMAN règle aussi JAVA_HOME pour toi.
Avec le gestionnaire de paquets¶
sudo apt install openjdk-25-jdk # Debian 13, Ubuntu récentes
sudo dnf install java-25-openjdk-devel # Fedora
Simple, mais tu dépends des versions packagées par ta distribution. Si plusieurs JDK cohabitent, sudo update-alternatives --config java choisit celui par défaut (Debian et Ubuntu).
Sur Windows et macOS, sans SDKMAN, prends l'installeur de adoptium.net.
À la main (archive Temurin)¶
C'est la méthode utilisée pour ce cours. Aucun droit root nécessaire :
mkdir -p ~/opt && cd ~/opt
curl -L -o jdk25.tar.gz \
"https://api.adoptium.net/v3/binary/latest/25/ga/linux/x64/jdk/hotspot/normal/eclipse"
tar xzf jdk25.tar.gz && rm jdk25.tar.gz # crée ~/opt/jdk-25.0.4.1+1
Puis ajoute à ton ~/.bashrc :
Vérifier l'installation¶
$ java -version
openjdk version "25.0.4.1" 2026-08-18 LTS
OpenJDK Runtime Environment Temurin-25.0.4.1+1 (build 25.0.4.1+1-LTS)
OpenJDK 64-Bit Server VM Temurin-25.0.4.1+1 (build 25.0.4.1+1-LTS, mixed mode, sharing)
$ javac -version
javac 25.0.4.1
Piège : JAVA_HOME
Maven, Gradle et les IDE ne regardent pas ton PATH : ils cherchent le JDK via la variable JAVA_HOME. Si java -version affiche 25 mais que Maven se plaint d'une autre version, c'est presque toujours JAVA_HOME qui pointe ailleurs (echo $JAVA_HOME).
Lancer un fichier directement¶
Crée Hello.java :
java compile le fichier en mémoire puis l'exécute : aucun .class n'est écrit sur le disque. C'est l'équivalent de python hello.py. Si ton fichier utilise des classes définies dans d'autres fichiers du même dossier, java les trouve et les compile aussi.
Deux formes de main¶
La forme compacte (Java 25)¶
Le fichier ci-dessus est un compact source file : des méthodes et des champs directement dans le fichier, sans déclarer de classe. Exemple un peu plus riche :
String salut(String nom) { // une méthode « libre »... en apparence
return "Salut " + nom;
}
void main() {
var noms = List.of("Ada", "Linus"); // List utilisable sans import
for (var n : noms) {
IO.println(salut(n));
}
}
// affiche :
// Salut Ada
// Salut Linus
mainn'a besoin ni depublic, ni destatic, ni de paramètre.IO.println(nouvelle classeIOde Java 25) remplaceSystem.out.println;IO.readln("question ? ")lit une ligne au clavier.- Tout le module
java.baseest importé d'office :List,Map,ArrayList... sont disponibles sansimport.
Sous le capot
Le compilateur enveloppe tout le fichier dans une classe implicite nommée d'après le fichier (javap montre final class Compact avec les méthodes salut et main). Il n'y a donc toujours pas de vraies fonctions libres en Java. Cette classe n'a pas de paquet et aucune autre classe ne peut la référencer : c'est fait pour les scripts et l'apprentissage, pas pour un projet.
La forme classique¶
C'est celle que tu verras partout, et celle qu'utilise Spring Boot :
public class Bonjour {
public static void main(String[] args) {
System.out.println("Bonjour, " + (args.length > 0 ? args[0] : "inconnu") + " !");
}
}
Mot par mot :
public class Bonjour: une classe visible de partout, qui porte le nom du fichier.public static void main: méthode visible par la JVM,staticdonc appelable sans créer d'objetBonjour, qui ne renvoie rien.String[] args: les arguments de la ligne de commande. Attention,args[0]est le premier argument, pas le nom du programme (contrairement àargv[0]en C++ ousys.argv[0]en Python).System.out.println:outest un champ statique de la classeSystem, de typePrintStream.
Pourquoi Spring garde-t-il cette forme ? Parce qu'une application Spring Boot démarre depuis une classe nommée, dans un paquet, sur laquelle on pose une annotation, et qu'on passe en paramètre :
@SpringBootApplication
public class TodoApplication {
public static void main(String[] args) {
SpringApplication.run(TodoApplication.class, args);
}
}
Une classe implicite n'a ni paquet ni nom utilisable : impossible d'écrire TodoApplication.class. Retiens donc : compacte pour les essais, classique pour les projets.
Compiler à la main : javac et java -cp¶
Dans un vrai projet, le code est rangé en paquets (un paquet = un dossier) et compilé à l'avance. Maven le fera pour toi, mais voir la mécanique une fois aide à comprendre les erreurs.
package xyz.dunkan.demo; // doit correspondre au dossier
public class App {
public static void main(String[] args) {
System.out.println(Salut.message("Duncan"));
}
}
package xyz.dunkan.demo;
class Salut { // pas public : visible dans le paquet seulement
static String message(String nom) {
return "Salut " + nom;
}
}
$ javac -d out src/xyz/dunkan/demo/*.java
$ find out -type f
out/xyz/dunkan/demo/Salut.class
out/xyz/dunkan/demo/App.class
$ java -cp out xyz.dunkan.demo.App
Salut Duncan
-d out: dossier de sortie ;javacy recrée l'arborescence des paquets.-cp out(classpath) : où la JVM cherche les classes, un peu commePYTHONPATH. On peut y mettre des dossiers et des.jar(archives zip de.class), séparés par:.- On lance une classe par son nom complet (paquet compris), pas par un chemin de fichier :
java -cp out Appéchoue avecClassNotFoundException: App.
Fichiers, classes et paquets¶
Les règles que le compilateur et les outils t'imposent :
- Une seule classe
publicpar fichier, et le fichier porte son nom exact (casse comprise). D'autres classes non publiques peuvent partager le fichier, mais c'est rare. - La déclaration
package xyz.dunkan.demo;correspond au dossierxyz/dunkan/demo/. Maven et les IDE l'exigent. - Pas besoin d'importer les classes du même paquet ; pour les autres, on écrit
import xyz.dunkan.autre.Truc;.
Mauvais.java:1: error: class Autre is public, should be declared in a file named Autre.java
public class Autre {
^
Piège : le lanceur est plus tolérant que javac
java Mauvais.java exécute ce fichier sans broncher, alors que javac le refuse (erreur ci-dessus). Ne te fie pas au lanceur pour valider l'organisation de ton code : Maven utilise javac.
Par rapport à ce que tu connais : pas de mod.rs ni de __init__.py, le dossier suffit à définir le paquet. Et contrairement aux modules Rust, les paquets ne sont pas hiérarchiques pour la visibilité : xyz.dunkan.demo.web n'a aucun accès privilégié à xyz.dunkan.demo.
jshell, la console interactive¶
jshell est le REPL de Java, l'équivalent de la console Python. Le point-virgule y est facultatif et chaque résultat est affiché :
$ jshell
jshell> int x = 40 + 2
x ==> 42
jshell> "abc".toUpperCase()
$2 ==> "ABC"
jshell> long fact(int n) { return n <= 1 ? 1 : n * fact(n - 1); }
| created method fact(int)
jshell> fact(20)
$4 ==> 2432902008176640000
| Commande | Effet |
|---|---|
/vars, /methods |
liste les variables, les méthodes définies |
/imports |
liste les imports actifs (tout java.base par défaut) |
/list |
réaffiche ce que tu as saisi |
/edit fact |
ouvre fact dans un éditeur |
/save f.jsh, /open f.jsh |
sauve ou recharge une session |
/reset, /exit |
repart de zéro, quitte |
Tab complète les noms de classes et de méthodes, et Shift+Tab puis I ajoute l'import manquant.
Choisir un IDE¶
Java est un langage verbeux à taper mais très outillé : un bon IDE complète, importe, renomme et génère du code à ta place.
- IntelliJ IDEA
- La référence pour Java et Spring (édité par JetBrains). La version gratuite suffit pour ce cours. Il détecte le JDK via
JAVA_HOMEou te propose d'en télécharger un. - VS Code
- Installe l'extension Extension Pack for Java (Microsoft), et plus tard le Spring Boot Extension Pack. Le moteur derrière est le serveur de langage d'Eclipse (
jdtls), utilisable aussi depuis Neovim ou Helix.
Raccourcis à apprendre en premier (IntelliJ)
Alt+Enter (corrections rapides et imports), Ctrl+Space (complétion), Shift+F6 (renommer), Alt+Ins (générer constructeur, getters, equals...). Sur macOS, certains changent (Option+Enter, Cmd+N pour générer).
Exercices¶
1. Écris un fichier compact Salut.java qui demande ton nom avec IO.readln et affiche « Salut nom, ton nom fait n lettres. ». Lance-le avec java Salut.java.
Solution
2. Réécris-le en forme classique, dans le paquet xyz.dunkan.hello, avec deux classes : Salut (le main) et Formules (non publique, avec une méthode static String saluer(String nom)). Compile dans out/ avec javac et lance avec java -cp.
Solution
package xyz.dunkan.hello;
public class Salut {
public static void main(String[] args) {
String nom = IO.readln("Ton nom ? "); // IO est utilisable partout
System.out.println(Formules.saluer(nom)); // même paquet : pas d'import
}
}
3. Dans jshell, définis la méthode fact vue plus haut, puis calcule fact(20) et fact(21). Que se passe-t-il ? Compare avec Long.MAX_VALUE.
Solution
jshell> fact(20)
$2 ==> 2432902008176640000
jshell> fact(21)
$3 ==> -4249290049419214848
jshell> Long.MAX_VALUE
$4 ==> 9223372036854775807
21! vaut environ 5,1 × 1019, plus que Long.MAX_VALUE (environ 9,2 × 1018). Le calcul déborde silencieusement et le résultat devient négatif : pas de panique comme en Rust en mode debug, pas d'entier illimité comme en Python. On voit comment s'en protéger au chapitre suivant.
À retenir¶
- Installe un JDK (pas un JRE), version 25 LTS, de préférence avec SDKMAN ; vérifie
JAVA_HOME. java Fichier.javacompile en mémoire et exécute : parfait pour apprendre et tester.- Forme compacte (
void main(),IO.println) pour les essais ; forme classique (public static void main(String[] args)) pour les projets et Spring. - Une classe publique par fichier, fichier nommé comme la classe ; paquet = dossier, nommé en domaine inversé.
javac -d outcompile,java -cp out paquet.Classeexécute ; Maven automatisera tout ça.- Garde
jshellouvert pour tester une API en deux secondes.