Java 25 : Compact Source Files (JEP 512)
Avec Java 25, la JEP 512 introduit les Compact Source Files
et les Instance Main Methods. Ces fonctionnalités permettent d'écrire des programmes
Java sans déclaration de classe explicite ni la fameuse signature public static void main(String[] args).
L'objectif : rendre Java plus accessible aux débutants et plus pratique pour le prototypage.
Cette nouveauté fait partie des JEPs (Java Enhancement Proposals) finalisées dans Java 25.
Le problème du boilerplate Java
Depuis sa création, Java est réputé pour sa verbosité. Le programme "Hello World" le plus simple nécessite une quantité surprenante de code :
// Hello World classique en Java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
Pour un débutant, ce code soulève immédiatement des questions :
- Pourquoi
public class? - Pourquoi
static? - Pourquoi
void? - Pourquoi
String[] argsalors qu'on ne les utilise pas ? - Pourquoi le fichier doit s'appeler
HelloWorld.java?
Ces concepts sont importants, mais ils créent une barrière à l'entrée pour l'apprentissage.
La solution Java 25 : écrire moins, faire plus
Avec Java 25, le même programme peut s'écrire ainsi :
// Hello World en Java 25 - c'est tout !
void main() {
System.out.println("Hello, World!");
}
Ou encore plus simple avec println directement disponible :
void main() {
println("Hello, World!");
}
Les deux fonctionnalités
1. Instance Main Methods
Java 25 accepte désormais plusieurs signatures pour la méthode main :
// Signature classique (toujours valide)
public static void main(String[] args) { }
// Nouvelles signatures Java 25
static void main(String[] args) { } // Sans public
static void main() { } // Sans arguments
void main(String[] args) { } // Sans static (instance method)
void main() { } // Minimale
La priorité de sélection si plusieurs méthodes main existent :
static void main(String[])static void main()void main(String[])void main()
2. Compact Source Files (Classes implicites)
Un fichier source peut contenir directement des méthodes et des champs sans déclaration de classe. Java crée automatiquement une classe implicite.
// Fichier: MonScript.java
// Pas de "public class MonScript" !
String greeting = "Bonjour";
void main() {
println(greeting + " depuis Java 25!");
}
void autreMethode() {
println("Une autre méthode");
}
Le compilateur crée automatiquement une classe implicite contenant ces membres.
Méthodes utilitaires disponibles
Dans les fichiers source compacts, plusieurs méthodes utilitaires sont automatiquement disponibles sans import ni préfixe :
void main() {
// Affichage simplifié
println("Texte avec saut de ligne");
print("Texte sans saut de ligne");
// Lecture de l'entrée utilisateur
String nom = readln("Entrez votre nom: ");
println("Bonjour " + nom);
}
Exemples pratiques
Script de calcul simple
// Fichier: Calculatrice.java
void main() {
double a = 10;
double b = 3;
println("Addition: " + (a + b));
println("Soustraction: " + (a - b));
println("Multiplication: " + (a * b));
println("Division: " + (a / b));
}
Programme interactif
// Fichier: Quiz.java
void main() {
println("=== Quiz Java 25 ===");
println();
int score = 0;
String r1 = readln("Quelle année est sorti Java 25? ");
if (r1.equals("2025")) {
println("Correct!");
score++;
} else {
println("Faux! C'était 2025.");
}
String r2 = readln("Combien de JEPs dans Java 25? ");
if (r2.equals("18")) {
println("Correct!");
score++;
} else {
println("Faux! Il y en a 18.");
}
println();
println("Score final: " + score + "/2");
}
Traitement de fichier
// Fichier: CompterLignes.java
import java.nio.file.*;
void main(String[] args) throws Exception {
if (args.length == 0) {
println("Usage: java CompterLignes.java <fichier>");
return;
}
Path fichier = Path.of(args[0]);
long lignes = Files.lines(fichier).count();
println("Le fichier " + args[0] + " contient " + lignes + " lignes.");
}
Utilisation d'APIs modernes
// Fichier: FetchUrl.java
import java.net.http.*;
import java.net.URI;
void main(String[] args) throws Exception {
String url = args.length > 0 ? args[0] : "https://api.github.com";
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create(url))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
println("Status: " + response.statusCode());
println("Body: " + response.body().substring(0, 200) + "...");
}
Exécution des fichiers source
Les fichiers source compacts peuvent être exécutés directement sans compilation explicite (fonctionnalité introduite dans Java 11, améliorée ici) :
# Exécution directe
java MonScript.java
# Avec arguments
java CompterLignes.java monfichier.txt
# Compilation classique (toujours possible)
javac MonScript.java
java MonScript
Champs et méthodes multiples
Un fichier source compact peut contenir plusieurs méthodes et champs :
// Fichier: GestionTaches.java
// Champs
List<String> taches = new ArrayList<>();
// Point d'entrée
void main() {
println("=== Gestionnaire de tâches ===");
while (true) {
println("\n1. Ajouter 2. Lister 3. Supprimer 4. Quitter");
String choix = readln("Choix: ");
switch (choix) {
case "1" -> ajouterTache();
case "2" -> listerTaches();
case "3" -> supprimerTache();
case "4" -> { println("Au revoir!"); return; }
default -> println("Choix invalide");
}
}
}
void ajouterTache() {
String tache = readln("Nouvelle tâche: ");
taches.add(tache);
println("Tâche ajoutée!");
}
void listerTaches() {
if (taches.isEmpty()) {
println("Aucune tâche.");
return;
}
for (int i = 0; i < taches.size(); i++) {
println((i + 1) + ". " + taches.get(i));
}
}
void supprimerTache() {
listerTaches();
if (taches.isEmpty()) return;
String index = readln("Numéro à supprimer: ");
try {
int i = Integer.parseInt(index) - 1;
String supprimee = taches.remove(i);
println("Supprimé: " + supprimee);
} catch (Exception e) {
println("Index invalide");
}
}
Limitations des classes implicites
Les fichiers source compacts ont quelques limitations :
- Pas de constructeur : impossible de définir un constructeur explicite
- Pas d'héritage : la classe implicite ne peut pas étendre une autre classe
- Pas d'interface : ne peut pas implémenter d'interfaces
- Package par défaut : la classe appartient au package non nommé
- Pas de référence externe : d'autres classes ne peuvent pas l'instancier
Quand utiliser cette fonctionnalité ?
Cas d'utilisation idéaux
- Apprentissage : pour les cours et tutoriels Java
- Prototypage rapide : tester une idée rapidement
- Scripts utilitaires : petits outils en ligne de commande
- Exploration d'APIs : tester une nouvelle bibliothèque
- Démonstrations : exemples de code concis
Quand éviter
- Applications de production : préférez la structure classique
- Code réutilisable : les classes explicites sont nécessaires
- Projets multi-fichiers : organisation en packages recommandée
Comparaison avec d'autres langages
Cette évolution rapproche Java d'autres langages de scripting :
# Python
print("Hello, World!")
# Kotlin
fun main() {
println("Hello, World!")
}
# Java 25
void main() {
println("Hello, World!");
}
Java reste plus verbeux que Python mais devient comparable à Kotlin pour les petits programmes.
Impact sur l'enseignement
Cette fonctionnalité est particulièrement importante pour l'éducation :
- Les étudiants peuvent écrire leur premier programme en 3 lignes
- Les concepts de base (variables, conditions, boucles) peuvent être enseignés sans la complexité OOP
- La transition vers les classes explicites peut se faire progressivement
- Les exercices pratiques deviennent plus concis
Conclusion
Les Compact Source Files et Instance Main Methods de Java 25 (JEP 512) représentent une évolution majeure pour l'accessibilité de Java. Sans sacrifier la puissance du langage, ces fonctionnalités permettent d'écrire du code simple de manière simple.
Pour les développeurs expérimentés, c'est un outil de productivité pour le prototypage. Pour les débutants, c'est une porte d'entrée beaucoup plus accueillante vers l'écosystème Java.