Aller au contenu

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 javac et lancer avec java -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 :

export JAVA_HOME="$HOME/opt/jdk-25.0.4.1+1"
export PATH="$JAVA_HOME/bin:$PATH"

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 :

Hello.java
void main() {
    IO.println("Bonjour depuis Java " + Runtime.version().feature());
}
$ java Hello.java
Bonjour depuis Java 25

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 :

Compact.java
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
  • main n'a besoin ni de public, ni de static, ni de paramètre.
  • IO.println (nouvelle classe IO de Java 25) remplace System.out.println ; IO.readln("question ? ") lit une ligne au clavier.
  • Tout le module java.base est importé d'office : List, Map, ArrayList... sont disponibles sans import.

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 :

Bonjour.java
public class Bonjour {
    public static void main(String[] args) {
        System.out.println("Bonjour, " + (args.length > 0 ? args[0] : "inconnu") + " !");
    }
}
$ java Bonjour.java Duncan
Bonjour, Duncan !

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, static donc appelable sans créer d'objet Bonjour, 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++ ou sys.argv[0] en Python).
  • System.out.println : out est un champ statique de la classe System, de type PrintStream.

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 :

TodoApplication.java (aperçu de la partie Spring)
@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.

src/xyz/dunkan/demo/App.java
src/xyz/dunkan/demo/Salut.java
src/xyz/dunkan/demo/App.java
package xyz.dunkan.demo;             // doit correspondre au dossier

public class App {
    public static void main(String[] args) {
        System.out.println(Salut.message("Duncan"));
    }
}
src/xyz/dunkan/demo/Salut.java
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 ; javac y recrée l'arborescence des paquets.
  • -cp out (classpath) : où la JVM cherche les classes, un peu comme PYTHONPATH. 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 avec ClassNotFoundException: App.

Fichiers, classes et paquets

Les règles que le compilateur et les outils t'imposent :

  1. Une seule classe public par fichier, et le fichier porte son nom exact (casse comprise). D'autres classes non publiques peuvent partager le fichier, mais c'est rare.
  2. La déclaration package xyz.dunkan.demo; correspond au dossier xyz/dunkan/demo/. Maven et les IDE l'exigent.
  3. 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_HOME ou 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
Salut.java
void main() {
    String nom = IO.readln("Ton nom ? ");
    IO.println("Salut " + nom + ", ton nom fait " + nom.length() + " lettres.");
}
$ java Salut.java
Ton nom ? Duncan
Salut Duncan, ton nom fait 6 lettres.

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
src/xyz/dunkan/hello/Salut.java
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
    }
}
src/xyz/dunkan/hello/Formules.java
package xyz.dunkan.hello;

class Formules {
    static String saluer(String nom) {
        return "Salut " + nom + ", ton nom fait " + nom.length() + " lettres.";
    }
}
$ javac -d out src/xyz/dunkan/hello/*.java
$ java -cp out xyz.dunkan.hello.Salut
Ton nom ? Duncan
Salut Duncan, ton nom fait 6 lettres.

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.java compile 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 out compile, java -cp out paquet.Classe exécute ; Maven automatisera tout ça.
  • Garde jshell ouvert pour tester une API en deux secondes.