0% ont trouvé ce document utile (0 vote)
7 vues227 pages

Ebook Java

Cet ebook, écrit par Philémon Globléhi, vise à enseigner Java de manière approfondie, en abordant des concepts allant de la programmation orientée objet à la programmation fonctionnelle. Il couvre l'évolution du langage Java, les outils nécessaires pour le développement, ainsi que les meilleures pratiques pour maîtriser le langage. Le document est conçu pour les débutants ainsi que pour ceux qui souhaitent approfondir leurs connaissances en Java.

Transféré par

akajeanpierrejoseph
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
7 vues227 pages

Ebook Java

Cet ebook, écrit par Philémon Globléhi, vise à enseigner Java de manière approfondie, en abordant des concepts allant de la programmation orientée objet à la programmation fonctionnelle. Il couvre l'évolution du langage Java, les outils nécessaires pour le développement, ainsi que les meilleures pratiques pour maîtriser le langage. Le document est conçu pour les débutants ainsi que pour ceux qui souhaitent approfondir leurs connaissances en Java.

Transféré par

akajeanpierrejoseph
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

MAÎTRISER

JAVA
COMME UN
PRO

DEVENEZ 10X PLUS


EFFICACE EN JAVA

PHILÉMON GLOBLÉHI
Java L'Essentiel:​
Maîtriser la POO et la
programmation
fonctionnelle

Philémon Globléhi​
Développeur Java
Version 1.0.0

Dernière mise à jour : 31/10/2025


Maîtriser Java : Du code à l'objet
Java, ce n'est pas juste un langage - c'est une manière de penser la programmation. Dans cet
ebook, on va démystifier ensemble les concepts qui font de Java un incontournable, de la simple
variable jusqu'aux architectures les plus élégantes.

Que tu débutes ou que tu veuilles consolider tes bases, on va explorer Java avec un objectif
simple : comprendre le pourquoi avant le comment.

Ce qu'on va explorer ensemble

Les fondations

●​ Pourquoi Java ? (et comment il s'est imposé)...........................................................................03


●​ Préparer ton environnement de travail…………………………………………………………………………..09
●​ Du code source au programme : comprendre la compilation………………………………………..11
●​ La grammaire de Java : ce qui rend ton code lisible………………………………………………………17

Construire avec les objets

●​ Ta première classe (et pourquoi c'est révolutionnaire).......................................................25


●​ Les types primitifs : les briques de base………………………………………………………………………33
●​ Manipuler les données : opérateurs et expressions…………………………………………………..39
●​ Diriger le flux : conditions et boucles…………………………………………………………………………..45
●​ Les tableaux : stocker et organiser………………………………………………………………………………52

La programmation orientée objet

●​ Attributs et méthodes : donner vie aux objets…………………………………………………………..58


●​ Naissance et mort d'un objet : le cycle de vie……………………………………………………………68
●​ Ranger ton code : les packages………………………………………………………………………………….76
●​ Héritage vs Composition : quand utiliser quoi ?.................................................................83
●​ Le polymorphisme démystifié……………………………………………………………………………………..91
●​ Classes abstraites : l'art de l'incomplétude……………………………………………………………….99
●​ Object : la mère de toutes les classes……………………………………………………………………….106
●​ String : bien plus qu'un simple texte…………………………………………………………………………..111
●​ Gérer l'imprévu : les exceptions…………………………………………………………………………………118
●​ Les énumérations : quand les constantes deviennent intelligentes……………………….127

Philémon GLOBLEHI, Développeur Java 1


●​ Les interfaces : des contrats en code……………………………………………………………….135

Aller plus loin

●​ Génériques : écrire du code réutilisable……………………………………………………………144


●​ Collections : gérer tes données comme un pro………………………………………………..152
●​ Lire et écrire : les entrées/sorties………………………………………………………………………160
●​ Manipuler le temps : les dates en Java……………………………………………………………..167
●​ Penser fonctionnel : lambdas…………………………………………………………………………….173
●​ Les streams : traiter les données en flux………………………………………………………….182
●​ Les classes internes : déclarer des classes dans des classes……………………….192
●​ Les nouveautés de Java 11 à Java 25………………………………………………………………202

Philémon GLOBLEHI, Développeur Java 2


Pourquoi Java ? (et comment il s’est imposé)

D'où vient Java ?


Java a vu le jour chez Sun Microsystems avant qu'Oracle ne reprenne les rênes en 2010. L'idée ?
Créer un langage qui marche partout, peu importe l'ordinateur sur lequel il tourne, tout en
profitant des avantages de la programmation orientée objet.

Comment ça fonctionne concrètement ?


Imaginez que vous écrivez une lettre, mais au lieu de l'envoyer directement, vous la traduisez
d'abord dans une langue intermédiaire que tout le monde peut comprendre. C'est exactement
ça, Java.

Quand vous écrivez du code Java, le compilateur le transforme en bytecode - pensez-y comme
un langage universel. Ensuite, la JVM (Java Virtual Machine) joue le rôle d'interprète : elle lit ce
bytecode et le traduit dans la langue que votre ordinateur comprend, au moment où vous lancez
le programme.

Ce qu'il faut retenir : Pour faire tourner un programme Java, vous avez besoin de deux choses :

●​ Le code compilé (fait par le développeur)


●​ La JVM installée sur votre machine

Quel environnement choisir ?


Oracle propose deux kits :

JRE - Pour simplement utiliser des applications Java. C'est comme avoir un lecteur DVD : vous
pouvez regarder des films, mais pas en créer.

JDK - Pour créer des applications Java. Là, vous avez la caméra ET le lecteur : vous pouvez
développer et tester vos programmes.

Philémon GLOBLEHI, Développeur Java 3


Open source ou propriétaire ?
Depuis 2006, Java est progressivement devenu open source (licence GNU GPL). Vous pouvez
donc choisir entre Open JDK (entièrement libre) ou la version Oracle qui, depuis Java 11,
nécessite une licence payante pour un usage professionnel en production.

L'évolution du langage Java


Java a connu une transformation remarquable depuis sa création. Voici les étapes clés de son
évolution, des débuts jusqu'aux versions les plus récentes.

Les débuts (1996-2004) : Poser les fondations


Java 1.0 (1996) marque la naissance du langage avec sa promesse "Write Once, Run Anywhere".
Les bases sont posées : classes, héritage, interfaces, exceptions.

Java 1.1 (1997) introduit les classes internes, la réflexion (introspection du code à l'exécution) et
JDBC pour accéder aux bases de données.

Java 1.2 (1998), rebaptisé Java 2, apporte le Java Collections Framework (listes, ensembles,
maps) qui remplace les anciennes structures Vector et Hashtable. Swing arrive pour créer des
interfaces graphiques modernes.

Java 1.4 (2002) ajoute les assertions, les expressions régulières intégrées, et l'API NIO (New I/O)
pour des entrées/sorties plus performantes.

La grande révolution (2004) : Java 5


Java 5 (2004) est un tournant majeur avec des fonctionnalités qui transforment l'écriture du code
:

●​ Génériques : enfin du code type-safe (List<String> au lieu de List)


●​ Autoboxing/Unboxing : conversion automatique entre int et Integer
●​ Énumérations : types énumérés riches et sûrs
●​ Annotations : métadonnées pour le code (@Override, @Deprecated)
●​ Varargs : nombre variable de paramètres (void method(String... args))

Philémon GLOBLEHI, Développeur Java 4


●​ For amélioré : boucle foreach simplifiée

Ces ajouts rendent Java beaucoup plus agréable et moins verbeux.

Maturation (2006-2011)
Java 6 (2006) se concentre sur les performances et l'outillage, sans grande nouveauté
syntaxique.

Java 7 (2011) apporte des améliorations pratiques :

●​ Try-with-resources : gestion automatique des ressources


●​ Notation diamant : List<String> liste = new ArrayList<>() (moins de
répétition)
●​ Switch sur les String : enfin possible !
●​ Littéraux numériques : 1_000_000 pour la lisibilité
●​ Catch multiple : catch (IOException | SQLException e)

L'ère moderne (2014) : Java 8


Java 8 (2014) est une révolution comparable à Java 5 :

●​ Lambdas et interfaces fonctionnelles : [Link](e ->


[Link](e))
●​ Streams API : manipulation déclarative des collections
●​ Méthodes par défaut dans les interfaces : évolution sans casser le code existant
●​ API Date/Time : [Link] remplace enfin Date et Calendar
●​ Optional : gérer l'absence de valeur sans null

La programmation fonctionnelle fait son entrée dans Java, rendant le code plus concis et
expressif.

Accélération du rythme (2017-aujourd'hui)


À partir de Java 9, Oracle adopte un rythme de release semestriel (mars et septembre).

Java 9 (2017) :

●​ Modules (Project Jigsaw) : modularisation du JDK

Philémon GLOBLEHI, Développeur Java 5


●​ JShell : REPL interactif pour tester du code
●​ Méthodes factory pour les collections : [Link](), [Link](), [Link]()

Java 10 (2018) :

●​ var : inférence de type local (var liste = new ArrayList<String>())

Java 11 (2018, LTS) :

●​ String enrichi : strip(), lines(), repeat(), isBlank()


●​ Simplification des fichiers source uniques (run direct sans compilation)
●​ Client HTTP modernisé

Java 12-13 (2019) :

●​ Switch expressions (preview) : int result = switch(day) { case MON, TUE


-> 1; default -> 0; }
●​ Blocs de texte (preview) : textes multilignes avec """

Java 14 (2020) :

●​ Records (preview) : classes de données immuables ultra-concises


●​ Pattern matching pour instanceof (preview) : if (obj instanceof String s)
●​ Switch expressions stabilisé

Java 15 (2020) :

●​ Blocs de texte stabilisés


●​ Sealed classes (preview) : contrôle fin de l'héritage

Java 16 (2021) :

●​ Records stabilisés
●​ Pattern matching pour instanceof stabilisé

Java 17 (2021, LTS) :

●​ Sealed classes stabilisées


●​ Suppression définitive du JIT expérimental AOT

Java 18-19 (2022) :

●​ Pattern matching pour switch (preview) : déconstruction dans les switch

Philémon GLOBLEHI, Développeur Java 6


●​ Serveur web simple intégré
●​ Virtual Threads (preview, Project Loom) : threads légers pour la concurrence massive

Java 20 (2023) :

●​ Continuation des previews (virtual threads, pattern matching)


●​ Scoped Values (preview) : alternative thread-safe aux ThreadLocal

Java 21 (2023, LTS) :

●​ Virtual Threads stabilisés : révolution pour la programmation concurrente


●​ Sequenced Collections : interfaces pour collections ordonnées
●​ Pattern Matching pour switch stabilisé
●​ Record Patterns : déconstruction des records dans les patterns

Java 22 (2024) :

●​ Unnamed Variables & Patterns : _ pour ignorer des valeurs


●​ String Templates (preview) : interpolation de chaînes sécurisée
●​ Statements avant super() : plus de flexibilité dans les constructeurs

Java 23 (2024) :

●​ Primitive Types in Patterns : pattern matching avec types primitifs (preview)


●​ Module Import Declarations : simplification des imports
●​ Markdown en Javadoc : documentation plus moderne

Java 24 (2025, mars) :

●​ Flexible Constructor Bodies : assouplissement des constructeurs (2nd preview)


●​ Stream Gatherers : nouvelles opérations intermédiaires pour les streams
●​ Améliorations des performances du garbage collector

Java 25 (2025, septembre, LTS) :

●​ Flexible Constructor Bodies stabilisé


●​ Améliorations continues du pattern matching
●​ Optimisations pour les virtual threads
●​ Raffinements du Project Valhalla (value types en preview attendu)

Philémon GLOBLEHI, Développeur Java 7


Les projets d'avenir
Plusieurs projets majeurs façonnent l'avenir de Java :

Project Loom : Virtual threads (désormais en production depuis Java 21) révolutionnent la
programmation concurrente avec des millions de threads légers.

Project Valhalla : Value types et generics spécialisés pour améliorer les performances et réduire
l'empreinte mémoire. Les premières previews sont attendues dans les prochaines versions.

Project Panama : Meilleure interopérabilité avec le code natif (C/C++), avec la Foreign Function &
Memory API en cours de finalisation.

Project Amber : Simplification continue de la syntaxe (pattern matching, records, switch


expressions...). Mission largement accomplie avec les versions récentes.

Les versions LTS


Certaines versions sont Long Term Support (LTS), supportées pendant des années :

●​ Java 8 (2014) : support jusqu'en 2030+


●​ Java 11 (2018) : support jusqu'en 2026+
●​ Java 17 (2021) : support jusqu'en 2029+
●​ Java 21 (2023) : support jusqu'en 2031+
●​ Java 25 (2025) : support jusqu'en 2033+

Les versions LTS sont désormais publiées tous les deux ans (au lieu de trois), facilitant l'adoption
des nouvelles fonctionnalités en production.

Ce qu'il faut retenir


Java a évolué d'un langage verbeux vers un langage moderne et expressif. Les lambdas et
streams (Java 8) ont introduit la programmation fonctionnelle. Le rythme semestriel accélère
l'innovation. Les records et le pattern matching réduisent considérablement le boilerplate. Les
virtual threads révolutionnent la concurrence. Java reste à la fois stable (LTS tous les deux ans) et
innovant (releases fréquentes), permettant à chacun de choisir son rythme d'adoption.

Philémon GLOBLEHI, Développeur Java 8


Préparer votre environnement de travail

Ce dont vous avez vraiment besoin


Pour démarrer en Java, deux outils sont indispensables :

Le JDK - Votre boîte à outils complète pour créer des programmes. Même si votre ordinateur
peut déjà exécuter des applications Java (grâce au JRE), ça ne suffit pas pour en développer. Le
JDK contient tout : le compilateur, la JVM, et plein d'utilitaires pratiques.

Un IDE - Votre atelier de développement. Techniquement, vous pourriez coder dans le


Bloc-notes, mais ce serait comme construire une maison avec juste un marteau. Un IDE vous
apporte l'assistance dont vous avez besoin : coloration du code, détection d'erreurs en temps
réel, suggestions intelligentes...

Installer le JDK
Rendez-vous sur le site d'Oracle pour télécharger le JDK 11 (ou une version plus récente selon
vos besoins). L'installation varie selon votre système :

●​ Windows/MacOS : un installeur classique, suivez simplement les étapes


●​ Linux : généralement via votre gestionnaire de paquets ou une archive à décompresser

Gardez en tête l'emplacement où vous installez le JDK, vous en aurez besoin après.

Choisir et configurer IntelliJ IDEA


IntelliJ IDEA est devenu l'IDE de référence pour beaucoup de développeurs Java. Il existe en
deux versions :

Community Edition (gratuite) - Parfaite pour débuter et créer des applications Java standard.
Largement suffisante pour apprendre.

Ultimate Edition (payante, mais gratuite pour les étudiants) - Ajoute le support avancé pour le
développement web, les bases de données, et d'autres frameworks professionnels.

Philémon GLOBLEHI, Développeur Java 9


Téléchargez simplement l'installeur depuis le site de JetBrains et laissez-vous guider.

Vérifier que tout fonctionne


Au premier lancement d'IntelliJ, l'IDE détecte normalement votre JDK automatiquement. Pour
vérifier :

1.​ Allez dans File → Project Structure (ou Ctrl+Alt+Shift+S)


2.​ Regardez la section SDKs dans la colonne de gauche
3.​ Votre JDK devrait apparaître ici

Pas de JDK détecté ? Pas de panique :

●​ Cliquez sur le + en haut


●​ Choisissez Add JDK...
●​ Naviguez jusqu'au dossier où vous l'avez installé
●​ Validez

Prêt à coder
Une fois ces étapes franchies, vous êtes paré ! IntelliJ vous proposera de créer votre premier
projet. Choisissez un projet Java simple, et vous verrez que l'IDE fait déjà beaucoup de travail
pour vous : structure de projet, suggestions, documentation intégrée...

Le vrai apprentissage commence maintenant : écrire votre premier programme Java.

Philémon GLOBLEHI, Développeur Java 10


Du code source au programme : comprendre
la compilation

Votre premier programme


Avant de plonger dans les subtilités du langage, voyons comment Java transforme votre code en
programme fonctionnel. Prenons cet exemple simple :

Ne vous inquiétez pas de la syntaxe pour le moment. Ce bout de code affiche juste "Bonjour le
monde !" quand vous le lancez.

Du code source au programme : la compilation


Votre fichier .java contient du texte lisible par un humain. Mais l'ordinateur, lui, ne comprend
que le bytecode. C'est là qu'intervient javac, le compilateur Java.

Ouvrez un terminal, placez-vous dans le dossier de votre fichier et tapez :

Philémon GLOBLEHI, Développeur Java 11


Si tout va bien, un nouveau fichier apparaît : [Link]. C'est votre bytecode,
prêt à être exécuté par la JVM. Impossible à lire pour vous, parfaitement clair pour la machine
virtuelle.

Astuce : Si votre terminal ne reconnaît pas javac, c'est que le chemin vers le JDK n'est pas
configuré. Donnez le chemin complet, par exemple :

Lancer votre programme


Maintenant que vous avez votre fichier .class, la JVM peut prendre le relais. Utilisez la
commande java suivie du nom de la classe sans l'extension :

Et voilà ! Votre message s'affiche. Notez qu'à ce stade, le fichier source .java n'est plus
nécessaire. Seul le .class compte pour l'exécution.

Philémon GLOBLEHI, Développeur Java 12


Les fichiers JAR : regrouper intelligemment
Imaginez un projet avec 500 fichiers .class. Distribuer tout ça séparément serait l'enfer ! Les
fichiers JAR (Java ARchive) résolvent ce problème : c'est simplement un fichier ZIP qui contient
tous vos .class, avec l'extension .jar.

Pour créer une archive :

Ensuite, ajoutez-la au classpath comme n'importe quel dossier :

Toutes les bibliothèques Java se distribuent sous forme de JAR. C'est pratique, compact, et ça
évite d'éparpiller des centaines de fichiers.

Travailler avec IntelliJ IDEA


Compiler à la main, c'est formateur, mais dans la vraie vie, vous utiliserez un IDE. IntelliJ fait tout
le sale boulot pour vous :

●​ Compilation automatique à chaque sauvegarde


●​ Détection des erreurs en temps réel avec des suggestions de correction
●​ Refactoring intelligent quand vous renommez une classe
●​ Navigation rapide dans votre code

Créer un projet

Philémon GLOBLEHI, Développeur Java 13


Dans IntelliJ : File → New → Project, choisissez Java, donnez un nom à votre projet, et c'est parti.
L'IDE crée automatiquement un dossier src pour vos sources.

Ajoutez-y votre fichier [Link], et IntelliJ le compile instantanément dès que


vous sauvegardez. Plus besoin de taper javac manuellement.

Quelques raccourcis à connaître

●​ Ctrl + Espace : autocomplétion (votre meilleur ami)


●​ Alt + Entrée : suggestions de correction
●​ Shift + F10 : lancer votre programme
●​ Ctrl + Alt + L : reformater le code proprement
●​ Shift + Shift : chercher n'importe quoi dans le projet

Ajouter une bibliothèque externe

Disons que vous voulez manipuler du JSON avec la bibliothèque Gson de Google. Téléchargez
le fichier JAR, créez un dossier lib dans votre projet, et copiez-y le JAR.

Ensuite : clic droit sur le JAR → Add as Library. IntelliJ s'occupe du reste.

Vous pouvez maintenant utiliser Gson dans votre code :

Philémon GLOBLEHI, Développeur Java 14


Lancez ce code, et vous obtenez une conversion automatique entre objets Java et JSON.
Magique, non ?

Exporter votre projet

Pour partager votre travail : Build → Build Artifacts → JAR. IntelliJ crée un fichier JAR contenant
tout votre code compilé, prêt à être distribué.

Ce qu'il faut retenir


Le cycle de vie d'un programme Java tient en trois étapes : écrire (fichiers .java), compiler
(fichiers .class), exécuter (via la JVM). Les fichiers JAR simplifient la distribution, et un bon IDE

Philémon GLOBLEHI, Développeur Java 15


comme IntelliJ automatise l'essentiel pour que vous puissiez vous concentrer sur votre code
plutôt que sur la plomberie.

Philémon GLOBLEHI, Développeur Java 16


La grammaire de Java : ce qui rend ton code
lisible

Les instructions : donnez vos ordres


Java est un langage impératif : vous écrivez une série d'ordres que la machine exécute dans
l'ordre. Chaque instruction se termine par un point-virgule. Simple, efficace.

Trois instructions, trois points-virgules. Le compilateur sait exactement où chacune commence et


finit.

Le typage : être explicite pour éviter les erreurs


Java ne tolère pas l'à-peu-près. Quand vous créez une variable, vous devez dire ce qu'elle va
contenir. C'est le typage fort.

Ici, age ne pourra contenir qu'un nombre entier. Si vous tentez d'y mettre du texte, le compilateur
vous arrête net :

Philémon GLOBLEHI, Développeur Java 17


Pourquoi c'est utile ? Parce que ça évite des bugs vicieux. Le compilateur joue le rôle de
garde-fou : il détecte les incohérences avant même que votre programme ne tourne.

Java vérifie les types deux fois : à la compilation (typage statique) et à l'exécution (typage
dynamique). Double sécurité.

Le raccourci var (depuis Java 10)

Parfois, le type est évident. Plutôt que de répéter l'information, utilisez var :

Le compilateur devine le type grâce à la valeur que vous assignez. Ça ne marche que si vous
initialisez immédiatement la variable, sinon Java ne peut pas deviner.

Les blocs : organiser son code


Les accolades {} délimitent des blocs de code. Elles regroupent plusieurs instructions
ensemble, souvent après un if, un while, ou une fonction.

Vous pouvez même créer des blocs anonymes pour isoler temporairement des variables :

Philémon GLOBLEHI, Développeur Java 18


Pas besoin de point-virgule après une accolade fermante.

Exemple complet :

Philémon GLOBLEHI, Développeur Java 19


Les commentaires : expliquez votre intention
Commentaires courts avec // :

Philémon GLOBLEHI, Développeur Java 20


Commentaires longs avec /* */ :

Commentaires javadoc pour générer de la documentation automatique, avec /** :

Le formatage : rendre le code lisible


Techniquement, Java se fiche complètement de la mise en forme. Vous pourriez tout écrire sur
une seule ligne. Mais pour les humains qui reliront votre code (vous y compris dans 6 mois), c'est
l'enfer.

Code illisible mais valide :

Philémon GLOBLEHI, Développeur Java 21


Même code, propre :

Les règles d'or

●​ Accolade ouvrante sur la même ligne, accolade fermante seule sur sa ligne
●​ Un espace autour des opérateurs : x = y + 2 plutôt que x=y+2
●​ Indentation (tabulation ou espaces) pour chaque niveau de bloc
●​ Retour à la ligne après chaque instruction

IntelliJ reformate automatiquement votre code avec Ctrl + Alt + L. Profitez-en

Les conventions de nommage : parler la même langue


Les développeurs Java sont pointilleux sur les noms. Respecter ces conventions rend votre code
immédiatement compréhensible.

Classes et interfaces : première lettre en majuscule, style chameau (PascalCase)

Méthodes et variables : première lettre en minuscule, style dromadaire (camelCase)

Philémon GLOBLEHI, Développeur Java 22


Constantes : tout en majuscules, mots séparés par des underscores

Packages : tout en minuscules

Soyez explicites. Préférez nombreInscriptions à nb ou n. Votre futur vous dira merci. Pour
les variables jetables dans une boucle, i, j, k restent acceptables.

Les mots réservés : terrain interdit


Certains mots appartiennent à Java et vous ne pouvez pas les utiliser comme noms de variables
ou de classes : if, while, class, int, public, return, new, this, etc.

À éviter aussi :

●​ true, false, null : valeurs spéciales


●​ _ (underscore seul) : réservé depuis Java 9

Si vous tentez d'utiliser int class = 5;, le compilateur refuse. Choisissez des noms qui ont
du sens, de toute façon.

Ce qu'il faut retenir

Philémon GLOBLEHI, Développeur Java 23


Java impose une structure claire : instructions terminées par ;, types explicites, blocs délimités
par {}. Le compilateur est strict, mais c'est pour votre bien : il attrape les erreurs tôt. Respectez
les conventions de nommage et de formatage, et votre code sera lisible par n'importe quel
développeur Java. C'est la base pour écrire du code maintenable.

Philémon GLOBLEHI, Développeur Java 24


Ta première classe (et pourquoi c’est
révolutionnaire)

Le principe de base

Java fonctionne sur un principe simple : tout est objet, ou presque. Un objet, c'est une
représentation informatique d'une entité concrète ou abstraite. Pour créer ces objets, on utilise
des classes, qui servent de moules ou de plans de construction.

Programmer en Java, c'est donc jongler entre trois activités : définir ces plans (les classes),
fabriquer des objets à partir de ces plans (l'instanciation), et faire travailler ces objets ensemble.

Créer sa première classe

Prenons un exemple différent : imaginons qu'on veuille modéliser un Compte bancaire pour une
application de gestion financière.

En Java, chaque classe vit dans son propre fichier. Le nom du fichier doit correspondre
exactement au nom de la classe, avec l'extension .java. Pour notre compte, on crée donc
[Link] :

Philémon GLOBLEHI, Développeur Java 25


Le mot-clé class lance la déclaration, précédé de public (on reviendra sur ce détail). Les
accolades délimitent le territoire de notre classe.

Ce qu'on peut mettre dans une classe

Une classe, c'est comme une boîte à outils qui peut contenir :

Des attributs - Ce sont les caractéristiques de l'objet, son ADN en quelque sorte. Notre compte
bancaire pourrait avoir un solde, un numéro de compte, etc.

Des méthodes - Les actions qu'on peut faire avec l'objet. Pour un compte : déposer de l'argent,
retirer, consulter le solde.

Des constantes - Des valeurs fixes qui donnent du sens au code.

Des énumérations et classes internes - Des structures plus avancées qu'on abordera plus tard.

L'ordre d'apparition de ces éléments est libre, mais par convention, on place généralement :
constantes, énumérations, attributs, puis méthodes.

Ajouter des comportements avec les méthodes

Enrichissons notre compte bancaire avec quelques méthodes. Commençons par consulter le
solde :

Philémon GLOBLEHI, Développeur Java 26


Une méthode suit toujours ce schéma :

[visibilité] [ce qu'elle renvoie] [son nom] ([ce qu'elle reçoit]) {

[les instructions]

Pour getSolde() :

●​ Visibilité : public (accessible de partout)


●​ Type de retour : double (un nombre décimal)
●​ Nom : getSolde
●​ Paramètres : aucun

L'attribut solde est marqué private - il reste invisible de l'extérieur. Par défaut, un double vaut
0.

Ajoutons maintenant des opérations bancaires :

Philémon GLOBLEHI, Développeur Java 27


Notez le mot-clé void pour les méthodes qui ne renvoient rien. La méthode toString() est
spéciale : elle génère une version texte de l'objet, utilisée notamment par
[Link](). L'opérateur + colle les textes ensemble et convertit
automatiquement les nombres en texte.

Philémon GLOBLEHI, Développeur Java 28


Le point d'entrée : la méthode main

Pour exécuter un programme, Java cherche une méthode particulière qui sert de porte d'entrée :

Toute classe peut avoir sa propre méthode main, ce qui signifie qu'une application peut avoir
plusieurs points de démarrage possibles. C'est pour ça qu'on doit préciser à la commande java
quelle classe lancer.

Ajoutons un petit programme de démonstration :

Philémon GLOBLEHI, Développeur Java 29


La ligne CompteBancaire compte = new CompteBancaire(); est cruciale. Une classe,
c'est juste un plan. Pour vraiment travailler avec un compte bancaire, on doit fabriquer une
instance concrète - un objet. Le mot-clé new déclenche cette fabrication et alloue de la mémoire
pour stocker l'état de l'objet.

Philémon GLOBLEHI, Développeur Java 30


Les parenthèses après new CompteBancaire() sont obligatoires.

Le point (.) sert à atteindre les méthodes de l'objet :

La classe System et son attribut out permettent d'afficher du texte. Quand on passe un objet à
println(), celui-ci appelle automatiquement la méthode toString() de l'objet.

Faire tourner le programme

En ligne de commande, placez-vous dans le dossier contenant votre fichier et tapez :

Résultat affiché :

Philémon GLOBLEHI, Développeur Java 31


Ce qu'il faut retenir
Une classe définit un modèle, une instance est un objet concret créé avec new. Les attributs
stockent l'état (souvent private), les méthodes définissent les actions (souvent public). Le
main est le point d'entrée du programme. L'opérateur . accède aux méthodes et attributs d'un
objet. Vous venez de créer vos premiers objets Java !

Philémon GLOBLEHI, Développeur Java 32


Les types primitifs : les briques de base

Pas tout à fait orienté objet


Java prétend être un langage orienté objet, mais il triche un peu. Il existe huit types primitifs qui
ne sont pas des objets, juste des valeurs stockées directement en mémoire. Pourquoi ? Pour des
raisons de performance : manipuler un simple nombre entier comme un objet serait lourd et
inefficace.

Voici les huit types primitifs :

Nombres entiers : byte, short, int, long

Nombres décimaux : float, double

Caractère : char

Booléen : boolean

Les booléens : vrai ou faux


Le type boolean ne connaît que deux valeurs : true ou false. C'est tout. Par défaut, un
attribut booléen vaut false.

Impossible d'utiliser un booléen dans un calcul mathématique. C'est une question de logique, pas
de nombre.

Les caractères : char

Philémon GLOBLEHI, Développeur Java 33


Un char stocke un seul caractère Unicode (UTF-16) sur 2 octets. On l'écrit entre apostrophes :

Les entiers : byte, short, int, long


Ces quatre types diffèrent uniquement par leur capacité de stockage :

●​ byte : 1 octet (-128 à 127)


●​ short : 2 octets (-32 768 à 32 767)
●​ int : 4 octets (-2 milliards à +2 milliards environ)
●​ long : 8 octets (vraiment très grand)

Par défaut, ils valent tous 0.

Règle simple : Vous pouvez affecter un type "petit" à un type "grand" sans problème. L'inverse
nécessite un cast avec risque de perte.

Pour un long, ajoutez le suffixe L :

Attention au dépassement : Si un calcul dépasse les limites du type, le nombre "boucle" sans
avertissement. Pour des calculs très grands, utilisez la classe BigInteger.

Philémon GLOBLEHI, Développeur Java 34


Les décimaux : float, double
Ces types représentent des nombres à virgule selon la norme IEEE 754.

●​ float : 4 octets (simple précision)


●​ double : 8 octets (double précision)

Par défaut, ils valent 0.0.

Vous pouvez mélanger entiers et décimaux :

Danger critique : Les nombres à virgule flottante sont approximatifs. Ne les utilisez jamais pour
de l'argent ou des calculs nécessitant une précision absolue. Pour ça, utilisez BigDecimal ou
stockez tout en centimes avec des int.

Les classes enveloppes : quand les primitifs ont besoin


d'être des objets

Philémon GLOBLEHI, Développeur Java 35


Parfois, vous devez traiter un nombre comme un objet (pour le mettre dans une collection, par
exemple). Java fournit des classes enveloppes :

●​ boolean → Boolean
●​ char → Character
●​ int → Integer
●​ byte → Byte
●​ short → Short
●​ long → Long
●​ float → Float
●​ double → Double

Ces classes offrent des méthodes utiles, comme convertir une chaîne en nombre :

Contrairement aux primitifs, ces objets peuvent être null (absence de valeur) :

Elles contiennent aussi des constantes utiles :

L'autoboxing : conversion automatique

Philémon GLOBLEHI, Développeur Java 36


Java convertit automatiquement entre primitifs et enveloppes quand nécessaire :

Le compilateur transforme ça en :

C'est pratique, mais attention aux pièges :

L'autoboxing fonctionne aussi avec les paramètres de méthode :

Quand l'utiliser ? L'autoboxing simplifie le code, mais il a un coût en performance. Si vous faites
des calculs intensifs, préférez les primitifs purs.

Ce qu'il faut retenir


Les types primitifs sont rapides et légers. Utilisez int pour les nombres entiers courants,
double pour les décimaux (sauf argent), boolean pour la logique, char pour les caractères

Philémon GLOBLEHI, Développeur Java 37


uniques. Les classes enveloppes permettent de traiter ces valeurs comme des objets quand
nécessaire. L'autoboxing facilite la conversion, mais peut cacher des bugs si vous oubliez le
risque de null. Choisissez toujours le type adapté à votre besoin : ni trop petit (risque de
dépassement), ni inutilement grand.

Philémon GLOBLEHI, Développeur Java 38


Manipuler les données : opérateurs et
expressions

L'affectation : copier des valeurs


L'opérateur = copie la valeur de droite dans la variable de gauche. Java fonctionne par copie.

Pour les objets, c'est différent : la variable stocke une référence (l'adresse mémoire de l'objet),
pas l'objet lui-même.

Si vous créez un nouvel objet, la référence change :

La valeur null signifie "ne pointe vers rien" :

Philémon GLOBLEHI, Développeur Java 39


Cette logique de copie par référence s'applique aussi aux paramètres de méthodes.

Les opérateurs arithmétiques


Opérations binaires (deux opérandes) :

Ordre de priorité : * et / avant + et -. Le reste de division : %

Opérations unaires (un seul opérande) :

Attention à la position de ++ et -- :

Philémon GLOBLEHI, Développeur Java 40


Préfixé : modifie d'abord, affecte ensuite. Postfixé : affecte d'abord, modifie après.

Concaténation de texte
L'opérateur + assemble des chaînes de caractères :

Java convertit automatiquement les nombres en texte. Même null devient le texte "null" :

En coulisses, Java utilise StringBuilder pour optimiser ces concaténations.

Les opérateurs de comparaison


Ces opérateurs retournent true ou false :

Piège avec les objets : == compare les références, pas le contenu !

Philémon GLOBLEHI, Développeur Java 41


Retenez bien : pour comparer des objets (surtout des String), utilisez toujours .equals(),
jamais ==.

Les opérateurs logiques


Pour combiner des conditions booléennes :

Optimisation automatique : Java n'évalue la partie droite que si nécessaire.

Pour && : si la gauche est false, inutile de vérifier la droite. Pour || : si la gauche est true,
inutile de vérifier la droite.

Si vous voulez forcer l'évaluation complète, utilisez & ou | (rare).

Philémon GLOBLEHI, Développeur Java 42


L'opérateur ternaire : condition en une ligne
Raccourci pour un if/else simple :

Format : condition ? valeur_si_vrai : valeur_si_faux

Pratique pour les affectations conditionnelles courtes.

Le transtypage (cast)
Forcer une conversion de type quand Java ne l'autorise pas automatiquement :

Si Java vous demande un cast, c'est souvent un signal : vérifiez que vous ne perdez pas de
données ou que votre logique est correcte.

Opérateurs combinés avec assignation


Raccourcis pour modifier et réaffecter :

Fonctionne aussi avec les opérateurs binaires : &=, |=, ^=, <<=, >>=.

Philémon GLOBLEHI, Développeur Java 43


L'opérateur point .
Accéder aux méthodes et attributs d'un objet :

On peut même l'utiliser directement sur une valeur littérale :

Ce qu'il faut retenir


L'affectation copie les valeurs (ou les références pour les objets). Les opérateurs arithmétiques
respectent les priorités classiques. Utilisez .equals() pour comparer des objets, jamais ==. Les
opérateurs logiques optimisent automatiquement l'évaluation. Le transtypage force une
conversion risquée. Les raccourcis comme += et ++ rendent le code plus concis. Maîtriser ces
opérateurs, c'est maîtriser les bases de toute logique Java.

Philémon GLOBLEHI, Développeur Java 44


Diriger le flux : conditions et boucles

Prendre des décisions avec if-else


Le if exécute un bloc de code uniquement si une condition est vraie :

Ajoutez else pour gérer le cas contraire :

Enchaînez plusieurs conditions avec else if :

Les accolades sont optionnelles pour une seule instruction, mais utilisez-les systématiquement
par clarté.

Sortir d'une méthode avec return

Philémon GLOBLEHI, Développeur Java 45


Le mot-clé return stoppe immédiatement l'exécution d'une méthode et renvoie une valeur :

Pour une méthode void, utilisez return seul pour sortir prématurément :

Le code après un return ne sera jamais exécuté (erreur "unreachable code").

Répéter avec while


Le while répète un bloc tant qu'une condition reste vraie :

La condition est testée avant chaque itération. Si elle est fausse dès le départ, le bloc ne
s'exécute jamais.

Philémon GLOBLEHI, Développeur Java 46


Répéter au moins une fois avec do-while
Variante du while qui garantit au moins une exécution :

La condition est testée après chaque itération.

La boucle for classique


Idéale pour itérer un nombre défini de fois :

Structure : initialisation ; condition ; incrément

Chaque partie peut être vide (mais gardez les points-virgules) :

Boucle infinie (à utiliser avec prudence) :

Philémon GLOBLEHI, Développeur Java 47


Le for amélioré (for-each)
Pour parcourir facilement des collections ou tableaux :

Format : for (type variable : collection). Plus lisible qu'un for classique quand vous
n'avez pas besoin de l'indice.

Contrôler les boucles avec break et continue


break sort complètement de la boucle :

continue passe directement à l'itération suivante :

Philémon GLOBLEHI, Développeur Java 48


Les libellés : pour les boucles imbriquées
Quand vous avez des boucles dans des boucles, un libellé permet de sortir de plusieurs niveaux
d'un coup :

Sans libellé, break ne sortirait que de la boucle interne.

Le switch : sélectionner parmi plusieurs valeurs


Alternative au if-else quand vous comparez une variable à plusieurs valeurs précises :

Philémon GLOBLEHI, Développeur Java 49


Important : Sans break, l'exécution continue dans les cas suivants (effet "cascade") :

Le switch fonctionne avec : entiers, caractères, chaînes de caractères, énumérations.

Ce qu'il faut retenir


Les structures de contrôle dirigent le flux d'exécution de votre programme. Le if-else prend
des décisions, les boucles (while, for) répètent des actions, break et continue affinent le
comportement des itérations, et switch simplifie les sélections multiples. Maîtriser ces outils,

Philémon GLOBLEHI, Développeur Java 50


c'est contrôler précisément la logique de vos programmes. Utilisez toujours des accolades pour
la lisibilité, même quand elles sont optionnelles.

Philémon GLOBLEHI, Développeur Java 51


Les tableaux : stocker et organiser

Qu'est-ce qu'un tableau ?


Un tableau stocke plusieurs valeurs du même type dans une seule variable. En Java, les tableaux
sont eux-mêmes des objets, ce qui signifie qu'une variable tableau peut valoir null.

Déclaration :

Créer et initialiser un tableau


Initialisation directe avec des valeurs :

Création avec new :

Quand vous créez un tableau sans valeurs initiales, Java remplit automatiquement avec des
valeurs par défaut :

●​ Nombres : 0 (ou 0.0)


●​ Booléens : false
●​ Objets : null

La taille peut être une variable :

Philémon GLOBLEHI, Développeur Java 52


Important : Une fois créé, un tableau a une taille fixe. Impossible d'ajouter ou retirer des
éléments. Pour changer la taille, il faut créer un nouveau tableau.

L'attribut length donne la taille (en lecture seule) :

Vous pouvez créer un tableau vide (new int[0]), mais une taille négative provoquera une
erreur à l'exécution.

Accéder aux éléments


Les indices commencent à 0. Le dernier élément est à l'indice length - 1.

Parcourir avec un for classique :

Parcourir avec un for amélioré (plus simple quand l'indice n'est pas nécessaire) :

Philémon GLOBLEHI, Développeur Java 53


Accéder à un indice hors limites provoque une erreur ArrayIndexOutOfBoundsException :

Tableaux multi-dimensionnels
Un tableau de tableaux, utile pour des matrices :

Les dimensions peuvent être irrégulières :

Afficher un tableau
Si vous affichez directement un tableau, vous obtenez quelque chose comme [I@ee7d9f1 (le
type et le code de hachage).

Pour voir le contenu, utilisez [Link]() :

Philémon GLOBLEHI, Développeur Java 54


Pour les tableaux multi-dimensionnels, utilisez [Link]().

Comparer des tableaux


L'opérateur == compare les références, pas le contenu :

Même equals() ne fonctionne pas comme attendu sur les tableaux. Utilisez
[Link]() :

Pour les tableaux multi-dimensionnels : [Link]().

Trier et rechercher
Trier un tableau :

Fonctionne aussi avec les chaînes et les objets comparables.

Recherche binaire (nécessite un tableau trié) :

Philémon GLOBLEHI, Développeur Java 55


Si l'élément n'existe pas, retourne un nombre négatif indiquant où il devrait être.

Copier un tableau
Créer une copie avec [Link]() :

Copier une portion avec [Link]() :

Copier entre tableaux existants avec [Link]() :

Le typage des tableaux


Un tableau conserve son type d'origine même si affecté à une variable de type parent :

Philémon GLOBLEHI, Développeur Java 56


Convertir un tableau en liste
Pour utiliser les collections Java, convertissez avec [Link]() :

Attention : la liste obtenue a une taille fixe (pas d'ajout/suppression possible), mais les éléments
sont modifiables.

Ce qu'il faut retenir


Les tableaux stockent des collections de taille fixe. Les indices commencent à 0. Utilisez
[Link]() pour afficher le contenu, [Link]() pour comparer,
[Link]() pour trier. Pour une copie, préférez [Link](). Le for amélioré
simplifie le parcours. Les tableaux ont des limites (taille fixe, pas de méthodes pratiques), c'est
pourquoi on préfère souvent les List et autres collections dans le code moderne. Mais
comprendre les tableaux reste essentiel, car ils restent utilisés dans de nombreuses API.

Philémon GLOBLEHI, Développeur Java 57


Attributs et méthodes : donner vie aux objets

Les attributs : l'état interne


Les attributs stockent les données d'un objet. Chaque instance a ses propres valeurs d'attributs.

Vous pouvez ensuite accéder à ces attributs :

Portée : public ou private

public : accessible partout dans le programme

private : accessible uniquement depuis la classe elle-même

La bonne pratique consiste à rendre les attributs private pour respecter l'encapsulation (on y
revient plus loin).

Valeurs par défaut

Même sans initialisation explicite, les attributs ont des valeurs par défaut :

●​ Nombres : 0 (ou 0.0)


●​ Booléens : false

Philémon GLOBLEHI, Développeur Java 58


●​ Objets : null

Vous pouvez initialiser directement :

Attributs finaux : figer une valeur

Le mot-clé final empêche toute modification après initialisation :

Une fois créé, impossible de changer nombreChapitres.

Attention : final interdit de changer la référence, pas l'état de l'objet référencé :

Philémon GLOBLEHI, Développeur Java 59


Attributs de classe (static)

Un attribut static est partagé par toutes les instances. Il appartient à la classe, pas aux objets
individuels.

Accessible directement depuis la classe :

Si vous modifiez un attribut static depuis une instance, tous les objets voient le changement :

Même si possible, évitez d'accéder aux attributs static via une instance, ça prête à confusion.
Passez toujours par le nom de la classe.

Constantes : static + final

Pour déclarer une vraie constante, combinez static et final :

Philémon GLOBLEHI, Développeur Java 60


Convention : nom en majuscules, mots séparés par _.

Les méthodes : les actions


Les méthodes définissent ce que vos objets peuvent faire.

Portée des méthodes

public : appelable partout (définit le contrat de la classe)

private : appelable uniquement depuis la classe (méthodes utilitaires internes)

Valeur de retour

Une méthode retourne au plus une valeur. Utilisez void si elle ne retourne rien.

Philémon GLOBLEHI, Développeur Java 61


Pour sortir prématurément d'une méthode void, utilisez return seul.

Paramètres

Les méthodes peuvent recevoir des paramètres :

Nombre variable de paramètres (varargs) avec ... :

Appel flexible :

Philémon GLOBLEHI, Développeur Java 62


Règles :

●​ Le paramètre variable doit être le dernier


●​ Vous pouvez aussi passer un tableau directement

Paramètres finaux empêchent toute réaffectation dans la méthode :

Variables locales

Déclarez des variables où vous voulez dans une méthode, mais initialisez-les avant usage
(contrairement aux attributs, elles n'ont pas de valeur par défaut) :

La portée d'une variable est limitée au bloc où elle est déclarée :

Philémon GLOBLEHI, Développeur Java 63


Méthodes de classe (static)
Une méthode static n'a pas accès aux attributs d'instance, seulement aux attributs static.
Elle fonctionne indépendamment de tout objet.

Appel direct depuis la classe :

La méthode main est static, c'est pourquoi elle peut démarrer sans créer d'objet.

Surcharge (overloading)
Plusieurs méthodes peuvent avoir le même nom si leurs paramètres diffèrent :

Philémon GLOBLEHI, Développeur Java 64


Le compilateur choisit automatiquement la bonne méthode selon les arguments.

Utilisez la surcharge pour des comportements similaires, pas pour des opérations totalement
différentes.

Le mot-clé this
this désigne l'instance courante. Utile quand un paramètre masque un attribut :

Vous pouvez aussi retourner this pour chaîner des appels :

this n'existe pas dans les méthodes static (elles n'ont pas d'instance).

Encapsulation : cacher l'état interne

Philémon GLOBLEHI, Développeur Java 65


Principe fondamental : rendez vos attributs private et offrez un accès contrôlé via des
méthodes publiques.

Pourquoi ? Pour découpler l'implémentation interne de l'interface publique. Les clients utilisent
votre objet sans connaître ses détails internes. Si vous changez l'implémentation plus tard, tant
que les méthodes publiques fonctionnent pareil, aucun impact.

Getters (accesseurs) et setters (mutateurs)

Au lieu d'exposer directement un attribut, créez des méthodes :

Getter (lecture) :

Pour un booléen, préférez is :

Setter (écriture) :

Classe complète avec encapsulation :

Philémon GLOBLEHI, Développeur Java 66


Les clients manipulent des doubles pages, mais l'état interne est en pages simples. Ils n'en
savent rien, et c'est parfait.

Vous contrôlez aussi quelles propriétés sont consultables ou modifiables :

●​ Pas de getter = propriété non consultable


●​ Pas de setter = propriété en lecture seule

IntelliJ peut générer automatiquement ces méthodes : clic droit → Generate → Getters and
Setters.

Ce qu'il faut retenir


Les attributs stockent l'état, les méthodes définissent le comportement. Utilisez private pour
les attributs (encapsulation), public pour les méthodes accessibles. Les attributs et méthodes
static appartiennent à la classe, pas aux instances. Le mot-clé this référence l'objet courant.
Les getters/setters offrent un accès contrôlé aux propriétés. La surcharge permet plusieurs
méthodes de même nom avec des paramètres différents. L'encapsulation cache les détails
d'implémentation et facilite l'évolution du code.

Philémon GLOBLEHI, Développeur Java 67


Naissance et mort d’un objet : le cycle de vie

Les constructeurs : initialiser correctement


Un constructeur est une méthode spéciale appelée automatiquement à la création d'un objet.
Son rôle : garantir que l'objet démarre dans un état cohérent.

Caractéristiques :

●​ Même nom que la classe


●​ Pas de type de retour (pas même void)
●​ Appelé avec new

Quand vous écrivez new CompteBancaire(), la JVM alloue la mémoire, appelle le


constructeur, puis retourne la référence de l'objet créé.

Constructeurs avec paramètres

Les constructeurs peuvent recevoir des paramètres pour initialiser l'objet :

Philémon GLOBLEHI, Développeur Java 68


Comme les méthodes, les constructeurs supportent la surcharge : plusieurs constructeurs avec
des paramètres différents.

Ordre d'initialisation

Java garantit cet ordre :

1.​ Initialisation des attributs (valeurs par défaut ou explicites)


2.​ Exécution du constructeur

Attributs final dans les constructeurs

Philémon GLOBLEHI, Développeur Java 69


Un attribut final doit être initialisé avant la fin du constructeur :

Le compilateur refuse :

●​ D'accéder à un final non initialisé


●​ De finir un constructeur sans initialiser tous les final
●​ De réassigner un final déjà initialisé

Le constructeur par défaut

Si vous ne déclarez aucun constructeur, le compilateur en génère un automatiquement


(constructeur par défaut, vide et public).

Attention : Dès que vous créez un constructeur (quel qu'il soit), le constructeur par défaut
disparaît.

Philémon GLOBLEHI, Développeur Java 70


Constructeur privé

Déclarez un constructeur private pour empêcher l'instantiation :

Utile pour les classes utilitaires qui ne contiennent que des méthodes static.

Chaîner les constructeurs

Un constructeur peut appeler un autre constructeur avec this(...) comme première


instruction :

Philémon GLOBLEHI, Développeur Java 71


Évite la duplication de code.

Appeler des méthodes dans un constructeur

Possible, mais prudence : tant que le constructeur n'est pas terminé, l'objet n'est pas
complètement initialisé.

Assurez-vous que l'état nécessaire est initialisé avant d'appeler une méthode.

Philémon GLOBLEHI, Développeur Java 72


Injection de dépendances
Plutôt que de créer les objets dont vous avez besoin dans le constructeur, recevez-les en
paramètre :

Mauvaise approche (couplage fort) :

Meilleure approche (injection) :

Utilisation :

Découple la création de l'utilisation. C'est la base de l'inversion de dépendances, un principe


fondamental en programmation objet.

Blocs d'initialisation (rarement utilisés)

Philémon GLOBLEHI, Développeur Java 73


Bloc d'instance : s'exécute avant chaque constructeur

Bloc static : s'exécute une seule fois au chargement de la classe

Rarement nécessaires, souvent remplaçables par des constructeurs ou des initialisations


directes.

Le ramasse-miettes (garbage collector)


Le ramasse-miettes libère automatiquement la mémoire des objets non référencés. Vous n'avez
pas à détruire manuellement les objets.

Un objet est considéré comme référencé si :

●​ Une variable active pointe vers lui

Philémon GLOBLEHI, Développeur Java 74


●​ Un autre objet référencé a un attribut qui pointe vers lui

Pour qu'un objet soit collecté :

●​ Aucune référence ne doit pointer vers lui

Le ramasse-miettes gère même les références circulaires (un objet qui se référence lui-même via
d'autres objets).

Vous pouvez suggérer un passage du ramasse-miettes avec [Link](), mais sans garantie
d'exécution immédiate. Le ramasse-miettes décide de son timing.

Attention : Le ramasse-miettes ne libère que la mémoire. Les autres ressources (fichiers,


connexions réseau) nécessitent une gestion explicite.

Ce qu'il faut retenir


Les constructeurs initialisent les objets à la création. Ils peuvent recevoir des paramètres et être
surchargés. L'injection de dépendances découple création et utilisation. Java gère
automatiquement la mémoire via le ramasse-miettes qui libère les objets non référencés. La
stack stocke les variables locales, le heap stocke les objets. Les constructeurs privés empêchent
l'instantiation. Chaîner les constructeurs avec this() évite la duplication. Le ramasse-miettes
fonctionne automatiquement, mais ne libère pas les ressources non-mémoire.

Philémon GLOBLEHI, Développeur Java 75


Ranger ton code : les packages

Le problème des collisions de noms


Imaginez deux développeurs qui créent chacun une classe GestionnaireDocument. Si ces
deux classes se retrouvent dans la même application, laquelle la JVM choisira-t-elle ? La
première trouvée, en ignorant l'autre. Catastrophe garantie.

Les packages résolvent ce problème en créant des espaces de noms distincts. Votre
GestionnaireDocument et celui d'un autre développeur peuvent coexister pacifiquement
dans des packages différents.

Déclarer un package
La première ligne d'un fichier Java (avant toute déclaration de classe) indique son package :

Règle importante : La structure des packages doit correspondre à l'arborescence des dossiers.

Si votre classe est dans package [Link], le fichier doit être dans :

Philémon GLOBLEHI, Développeur Java 76


Le compilateur respecte automatiquement cette structure pour les fichiers .class.

Le package par défaut (à éviter)

Sans déclaration package, votre classe appartient au package par défaut (sans nom). C'est
pratique pour des tests rapides, mais ne faites jamais ça en production. IntelliJ vous alertera
d'ailleurs. Tous vos fichiers doivent appartenir à un package nommé.

Sous-packages : organiser l'arborescence


Les packages s'organisent de manière hiérarchique, comme des dossiers :

Sur le disque :

Convention de nommage
Pour éviter toute collision, utilisez votre nom de domaine inversé comme base :

●​ Domaine : [Link]
●​ Package : [Link]

Puis ajoutez le nom de l'application ou de la bibliothèque.

Philémon GLOBLEHI, Développeur Java 77


Noms réservés : Les packages commençant par java ou javax sont réservés à l'API standard.
N'y touchez pas.

Le nom complet d'une classe


Une classe est désignée par son nom complet : package + nom de classe.

La classe String s'appelle en réalité [Link]. Vous pourriez créer votre propre
classe String dans un autre package sans conflit :

Pour utiliser une classe depuis un autre package, utilisez son nom complet :

Exception : Vous avez automatiquement accès aux classes de votre propre package et du
package [Link] (d'où l'usage direct de String, Math, System...).

Import : simplifier l'accès

Philémon GLOBLEHI, Développeur Java 78


Pour éviter de répéter les noms complets, importez les classes nécessaires :

Types d'imports

Importer une classe :

Importer une méthode ou attribut static :

Importer toutes les classes d'un package :

Philémon GLOBLEHI, Développeur Java 79


Déconseillé ! Même si pratique, ça rend le code moins clair. IntelliJ gère les imports
automatiquement (Ctrl + Alt + O pour les réorganiser). Autant être explicite.

Exemple complet :

Si un nom importé entre en conflit avec un nom local, l'import est ignoré. Utilisez alors le nom
complet pour lever l'ambiguïté.

Portée package : cacher l'implémentation

Philémon GLOBLEHI, Développeur Java 80


Jusqu'ici : public (accessible partout) et private (accessible uniquement dans la classe).

Il existe une troisième portée, sans mot-clé : la portée package. Accessible uniquement depuis
le même package.

La classe CryptoAlgo est invisible hors du package [Link]. Seule


CryptoUtils est exposée publiquement. Ça cache la complexité interne et simplifie l'API.

Le fichier [Link]
Fichier spécial (optionnel) dans chaque package pour documenter le package lui-même :

Philémon GLOBLEHI, Développeur Java 81


Utile pour générer de la documentation Javadoc complète. Peut aussi contenir des annotations
de package.

Ce qu'il faut retenir


Les packages créent des espaces de noms pour éviter les collisions. Organisez-les selon votre
nom de domaine inversé. La structure des packages doit refléter l'arborescence des dossiers.
Importez les classes nécessaires pour éviter les noms complets répétitifs. La portée package
(sans mot-clé) cache l'implémentation aux classes externes. IntelliJ gère automatiquement les
imports, profitez-en. Ne laissez jamais une classe dans le package par défaut. Les packages
structurent votre code et facilitent sa maintenance à long terme.

Philémon GLOBLEHI, Développeur Java 82


Héritage vs Composition : quand utiliser
quoi

Deux types de relations fondamentales


En programmation objet, les classes entretiennent deux relations principales :

"Est un" (is-a) : héritage - une classe est un cas particulier d'une autre "A un" (has-a) :
composition - une classe utilise les services d'une autre

L'héritage : factoriser le code commun


Imaginez une bibliothèque numérique avec des livres papier et des livres audio. Ces deux
classes partagent des caractéristiques (titre, auteur) mais ont aussi leurs spécificités.

Plutôt que dupliquer le code, créez une classe parente générale :

Philémon GLOBLEHI, Développeur Java 83


Les classes enfants héritent avec extends :

LivreAudio et LivrePoche héritent automatiquement de afficher() et modifier(), tout


en ajoutant leurs propres méthodes.

Appeler le constructeur parent

Un constructeur enfant doit initialiser la partie héritée. Utilisez super() comme première
instruction :

Philémon GLOBLEHI, Développeur Java 84


Si vous n'appelez pas explicitement super(), le compilateur ajoute automatiquement super()
(sans paramètre). Si le parent n'a pas de constructeur vide, erreur de compilation.

La racine universelle : Object

Java n'autorise pas l'héritage multiple (une seule classe parente). Toute classe sans extends
hérite automatiquement de Object.

Toutes les classes Java descendent donc d'Object, d'où les méthodes universelles
toString(), equals(), hashCode().

Substituabilité : utiliser les types parents


Une classe enfant peut être affectée à une variable de type parent (upcasting) :

Puisque LivreAudio est un Livre, vous pouvez traiter un livre audio comme un livre générique.
Utile pour écrire du code qui fonctionne avec n'importe quel type de livre.

Toute instance peut même être affectée à Object :

Philémon GLOBLEHI, Développeur Java 85


Downcasting : revenir au type enfant

L'inverse (downcasting) nécessite un cast explicite et peut échouer :

Vérifier le type avec instanceof

Sécurisez vos downcasts avec instanceof :

Le downcasting devrait rester exceptionnel. Si vous l'utilisez partout, repensez votre architecture.

Les portées : contrôler l'accès

Philémon GLOBLEHI, Développeur Java 86


Quatre niveaux de visibilité, du plus ouvert au plus fermé :

public : accessible partout protected : accessible dans le package ET par les classes enfants
(même dans d'autres packages) package (pas de mot-clé) : accessible uniquement dans le
package private : accessible uniquement dans la classe

Pourquoi protected ?

Si un attribut est private, les classes enfants n'y ont pas accès. Utilisez protected quand les
enfants doivent pouvoir lire/modifier l'attribut.

Règle générale : Déclarez tout private par défaut. Passez à protected uniquement si
nécessaire. Ça limite les risques de modification involontaire de l'état interne.

Héritage des membres static


Les méthodes et attributs static sont partagés dans toute la hiérarchie :

Philémon GLOBLEHI, Développeur Java 87


Le compteur est unique pour toute la hiérarchie. Invoquez de préférence via la classe où c'est
déclaré pour la clarté.

Classes final : bloquer l'héritage


Une classe final ne peut pas être étendue :

Cas d'usage rare. Exemple célèbre : String est final, impossible d'en hériter.

La composition : utiliser d'autres objets


La composition signifie qu'une classe contient des instances d'autres classes comme attributs.

Philémon GLOBLEHI, Développeur Java 88


Un livre a des pages. C'est la composition. Plus courante que l'héritage en pratique.

Héritage vs Composition : quand utiliser quoi ?


Héritage : quand une classe est vraiment un type spécialisé d'une autre

●​ Une voiture est un véhicule


●​ Un carré est un rectangle (attention aux pièges !)

Composition : quand une classe utilise une autre

●​ Une voiture a un moteur


●​ Une voiture a des pneus
●​ Un garage contient des véhicules

Philémon GLOBLEHI, Développeur Java 89


Préférez la composition quand possible. L'héritage crée un couplage fort. La composition reste
flexible.

Ce qu'il faut retenir


L'héritage modélise une relation "est un" avec extends. Une classe enfant hérite des attributs et
méthodes de son parent. Appelez le constructeur parent avec super(). Toutes les classes
héritent d'Object. Le polymorphisme permet d'affecter un enfant à une variable parent. Utilisez
instanceof avant un downcast. La portée protected rend accessible aux enfants. Les
membres static sont partagés dans toute la hiérarchie. La composition (relation "a un") se fait
via des attributs. Privilégiez la composition sur l'héritage quand les deux sont possibles.

Philémon GLOBLEHI, Développeur Java 90


Le polymorphisme démystifié

Principe fondamental
Le polymorphisme permet aux classes enfants de redéfinir le comportement des méthodes
héritées. Chaque type d'objet peut réagir différemment au même appel de méthode.

Le comportement dépend du type réel de l'objet, pas du type de la variable :

Philémon GLOBLEHI, Développeur Java 91


Même si les deux variables sont de type Employe, chacune exécute la méthode correspondant
à son objet réel.

Redéfinir une méthode : les règles


Pour redéfinir correctement :

Signature identique : même nom, mêmes paramètres Portée égale ou plus large : protected
→ public autorisé, l'inverse interdit Type de retour compatible : peut être un sous-type du
retour original

Élargir la portée

Vous pouvez rendre une méthode plus accessible dans l'enfant :

Utile pour cacher une implémentation au niveau parent tout en laissant l'enfant l'exposer
publiquement si nécessaire.

Philémon GLOBLEHI, Développeur Java 92


Type de retour spécialisé

Le type de retour peut être un sous-type :

Le mot-clé super : appeler le parent


super permet d'accéder à l'implémentation parente :

Limitation : super n'accède qu'au parent direct. Impossible de sauter plusieurs niveaux dans la
hiérarchie.

L'annotation @Override : sécuriser vos redéfinitions


Ajoutez @Override avant toute méthode redéfinie. Le compilateur vérifie qu'elle correspond
bien à une méthode parente :

Philémon GLOBLEHI, Développeur Java 93


Sans @Override, une erreur de nom crée silencieusement une nouvelle méthode au lieu de
redéfinir l'existante. Avec, le compilateur vous alerte immédiatement.

Ce qui ne supporte PAS le polymorphisme

Méthodes private

Les méthodes private ne sont pas héritées, donc pas redéfinissables. Deux méthodes
private de même nom dans parent et enfant sont totalement distinctes.

Méthodes static

Les méthodes static appartiennent à la classe, pas aux instances. Pas de redéfinition possible :

Philémon GLOBLEHI, Développeur Java 94


Appelez toujours les méthodes static via le nom de classe pour éviter la confusion.

Méthodes final : bloquer la redéfinition


Une méthode final ne peut pas être redéfinie :

Rare en pratique. Utilisez final uniquement si le comportement doit absolument rester


identique dans toute la hiérarchie.

Piège : polymorphisme dans les constructeurs


Danger : Appeler une méthode redéfinie dans un constructeur peut causer des bugs difficiles à
tracer.

Philémon GLOBLEHI, Développeur Java 95


Le constructeur parent appelle afficher() avant que l'enfant n'ait initialisé certificat.
Résultat : NullPointerException.

Solution : N'appelez dans les constructeurs que des méthodes private ou final qui ne
peuvent pas être redéfinies.

Masquage des attributs (à éviter)


Vous pouvez déclarer un attribut du même nom qu'un attribut parent, mais ça ne redéfinit rien, ça
masque juste :

Philémon GLOBLEHI, Développeur Java 96


Source de confusion. Évitez absolument cette pratique, utilisez des noms différents.

Le principe du ouvert/fermé
Une classe doit être :

●​ Ouverte à l'extension : on peut ajouter de nouvelles méthodes par héritage


●​ Fermée à la modification : on ne doit pas altérer le comportement existant

Comment l'appliquer :

●​ Attributs en private (inaccessibles aux enfants)


●​ Méthodes critiques en final (non redéfinissables)
●​ Redéfinition pour étendre, pas pour casser le contrat parent

Une classe enfant ne devrait jamais redéfinir une méthode d'une façon qui violerait les attentes
des utilisateurs de la classe parent.

Ce qu'il faut retenir

Philémon GLOBLEHI, Développeur Java 97


Le polymorphisme permet aux enfants de modifier le comportement hérité via la redéfinition. Le
comportement exécuté dépend du type réel de l'objet, pas du type de la variable. Utilisez
@Override systématiquement pour sécuriser vos redéfinitions. super accède à
l'implémentation parente. Les méthodes private et static ne supportent pas le
polymorphisme. Les méthodes final bloquent la redéfinition. Évitez d'appeler des méthodes
redéfinissables dans les constructeurs. Ne masquez jamais les attributs parents. Respectez le
principe du ouvert/fermé : étendez sans casser le contrat.

Philémon GLOBLEHI, Développeur Java 98


Classes abstraites : l’art de l’incomplétude

Pourquoi abstraire ?
Parfois, une classe parente représente un concept tellement général qu'il n'a pas de sens de
créer directement ses instances. La classe Document sert à mutualiser le code commun aux PDF
et aux fichiers Word, mais créer un "document générique" sans préciser son type concret n'a pas
vraiment d'utilité.

Les classes abstraites résolvent ce problème : elles définissent un modèle sans pouvoir être
instanciées directement.

Déclarer une classe abstraite


Ajoutez le mot-clé abstract :

Impossible maintenant de créer directement un Document :

Philémon GLOBLEHI, Développeur Java 99


Par contre, les classes enfants concrètes restent instanciables :

Une classe abstraite doit avoir au moins une classe enfant concrète, sinon elle ne sert à rien.
C'est pourquoi abstract et final sont incompatibles (une classe final ne peut pas avoir
d'enfants).

Méthodes abstraites : imposer un contrat


Une méthode abstraite déclare une signature sans corps. Les classes enfants concrètes doivent
obligatoirement l'implémenter.

Les enfants doivent fournir l'implémentation :

Philémon GLOBLEHI, Développeur Java 100


Si une classe concrète hérite d'une méthode abstraite sans la redéfinir : erreur de compilation.

Pourquoi des méthodes abstraites ?

Définir des propriétés variables

Au lieu de stocker nombrePages comme attribut, on le définit comme propriété abstraite.


Chaque type de véhicule retourne sa propre valeur.

Personnaliser un algorithme

Une classe abstraite peut implémenter un algorithme général qui appelle des méthodes
abstraites à des points précis. Les enfants adaptent le comportement en implémentant ces
méthodes.

Philémon GLOBLEHI, Développeur Java 101


Les classes enfants héritent de tout l'algorithme traiter() mais contrôlent ce qui s'affiche via
getContenu() :

Philémon GLOBLEHI, Développeur Java 102


C'est le patron de conception Template Method : l'algorithme est fixe dans le parent, les détails
sont personnalisables par les enfants.

Règles à retenir
Une classe abstraite peut avoir :

●​ Des méthodes abstraites (sans corps)


●​ Des méthodes concrètes (avec corps)
●​ Des attributs
●​ Des constructeurs (appelés par les enfants via super())

Une classe abstraite ne peut pas :

●​ Être instanciée directement


●​ Être final (incompatible avec abstract)

Une méthode abstraite :

●​ N'a pas de corps ( juste signature + ;)


●​ Force les enfants concrets à l'implémenter
●​ Peut avoir n'importe quelle portée sauf private

Une classe enfant abstraite :

●​ Peut hériter de méthodes abstraites sans les implémenter

Philémon GLOBLEHI, Développeur Java 103


●​ Reporte l'obligation d'implémentation à ses propres enfants concrets

Exemple complet

Utilisation :

Philémon GLOBLEHI, Développeur Java 104


Ce qu'il faut retenir
Les classes abstraites modélisent des concepts généraux non instanciables directement. Le
mot-clé abstract empêche l'instanciation. Les méthodes abstraites imposent un contrat que les
enfants concrets doivent respecter. Utilisez l'abstraction pour factoriser le code commun tout en
laissant les détails variables aux enfants. Une classe abstraite mêle code réutilisable (méthodes
concrètes) et contrats à respecter (méthodes abstraites). C'est un outil puissant pour créer des
hiérarchies de classes cohérentes et extensibles.

Philémon GLOBLEHI, Développeur Java 105


Object : la mère de toutes les classes

La racine de tout
Java n'autorise que l'héritage simple. Toute classe sans extends hérite automatiquement
d'Object. Résultat : toutes les classes Java descendent d'Object.

Object fournit des méthodes communes à toutes les classes. Certaines méritent d'être
redéfinies pour fonctionner correctement.

Rien ne vous empêche de créer une instance d'Object directement, même si ça n'a pas grand
intérêt :

La méthode equals() : comparer correctement


Règle d'or : N'utilisez jamais == pour comparer des objets. == compare les références, pas le
contenu.

Utilisez toujours equals() :

Philémon GLOBLEHI, Développeur Java 106


Redéfinir equals()

L'implémentation par défaut d'Object compare simplement les références (this == obj).
Souvent insuffisant.

Si votre classe a une notion d'identité (un ID, une désignation...), redéfinissez equals() :

Deux produits sont égaux s'ils ont le même code barre.

La méthode hashCode() : pour les tables de hachage

Philémon GLOBLEHI, Développeur Java 107


Si vous redéfinissez equals(), redéfinissez toujours hashCode() aussi. Sinon, vos objets ne
fonctionneront pas correctement dans les HashMap, HashSet, etc.

Règle : Deux objets égaux (selon equals()) doivent avoir le même hashCode().

Basez-vous sur les mêmes attributs que dans equals().

IntelliJ peut générer ces deux méthodes automatiquement : Generate → equals() and
hashCode().

La méthode toString() : déboguer facilement


toString() retourne une représentation textuelle de votre objet. Utilisée implicitement lors de
la concaténation :

Par défaut, Object retourne quelque chose comme Produit@1a2b3c4d (nom de classe +
hashcode). Peu utile.

Redéfinissez pour plus de clarté :

Résultat :

Philémon GLOBLEHI, Développeur Java 108


Très pratique pour le débogage et les logs.

La méthode clone() : copier des objets


clone() crée une copie d'un objet. Par défaut, elle est protected et lance une exception sauf
si votre classe implémente l'interface Cloneable.

Attention : Le clonage par défaut est superficiel. Si vos attributs sont des objets, seules les
références sont copiées, pas les objets eux-mêmes.

Les tableaux implémentent automatiquement Cloneable :

La méthode getClass() : introspection


getClass() retourne l'objet représentant la classe de l'instance. Utile pour la réflexion :

Philémon GLOBLEHI, Développeur Java 109


Permet d'accéder dynamiquement aux informations de la classe au moment de l'exécution.

La méthode finalize() : avant la destruction


Appelée par le ramasse-miettes avant destruction, mais sans aucune garantie de quand ni
même si elle sera exécutée. Peu fiable, évitez de vous en servir.

Méthodes de concurrence
Object fournit aussi wait(), notify(), notifyAll() pour la programmation concurrente
(threads). Sujet avancé, hors de portée pour débuter.

Ce qu'il faut retenir


Toutes les classes héritent d'Object. N'utilisez jamais == pour comparer des objets, utilisez
equals(). Si vous redéfinissez equals(), redéfinissez aussi hashCode(). Redéfinissez
toString() pour faciliter le débogage. clone() nécessite Cloneable et fait une copie
superficielle par défaut. getClass() permet l'introspection. finalize() est peu fiable,
évitez-la. Ces méthodes forment le socle commun à tous les objets Java.

Philémon GLOBLEHI, Développeur Java 110


String : bien plus qu’un simple texte

Les chaînes de caractères : des objets immuables


En Java, les chaînes de caractères sont des instances de String. Elles s'écrivent entre
guillemets :

Différence importante : Une String n'est pas un tableau. Pour accéder aux caractères, utilisez
charAt() :

Ou convertissez en tableau avec toCharArray() :

Méthodes essentielles

Comparaison

Ne jamais utiliser == pour comparer des String ! Utilisez equals() :

Philémon GLOBLEHI, Développeur Java 111


Ignorer la casse :

Comparaison lexicographique (ordre alphabétique) :

Recherche

Modification (création d'une nouvelle chaîne)

Extraction

Philémon GLOBLEHI, Développeur Java 112


Concaténation

Immutabilité : les String ne changent jamais


Crucial : Une fois créée, une String ne peut pas être modifiée. Toutes les méthodes créent de
nouvelles chaînes :

Cette immutabilité permet :

●​ De déclarer des constantes fiables (static final String)


●​ Des optimisations mémoire par la JVM

La JVM réutilise les littéraux identiques :

Philémon GLOBLEHI, Développeur Java 113


StringBuilder : construire efficacement
Pour construire des chaînes par concaténations multiples, utilisez StringBuilder (mutable,
donc plus performant) :

Autres opérations :

D'ailleurs, le compilateur transforme automatiquement les concaténations + en StringBuilder


:

Formatage de texte
[Link]() permet de créer des chaînes formatées :

Philémon GLOBLEHI, Développeur Java 114


Principaux codes de conversion

●​ %s : chaîne de caractères
●​ %d : entier décimal
●​ %f : nombre à virgule
●​ %c : caractère
●​ %b : booléen
●​ %% : le caractère %
●​ %n : retour à la ligne

Options de formatage

Avec une locale :

Expressions régulières
Les regex permettent de vérifier, chercher et remplacer des motifs complexes.

Vérifier un motif

Philémon GLOBLEHI, Développeur Java 115


Classes de caractères

●​ . : n'importe quel caractère


●​ \d : chiffre (0-9)
●​ \w : caractère de mot (lettres, chiffres, _)
●​ \s : espace blanc
●​ [abc] : a, b ou c
●​ [a-z] : lettre minuscule
●​ [^0-9] : tout sauf chiffre

Quantificateurs

●​ ? : 0 ou 1 fois
●​ * : 0 ou plusieurs fois
●​ + : 1 ou plusieurs fois
●​ {n} : exactement n fois
●​ {n,m} : entre n et m fois

Remplacer avec regex

Découper une chaîne

Philémon GLOBLEHI, Développeur Java 116


Ce qu'il faut retenir
Les String sont immuables, toute modification crée une nouvelle chaîne. Utilisez toujours
equals() pour comparer, jamais ==. Pour des constructions multiples, préférez
StringBuilder. [Link]() simplifie le formatage. Les expressions régulières offrent
une puissance énorme pour la manipulation de texte. La classe String est finale, impossible
d'en hériter. Maîtriser les chaînes de caractères est essentiel, elles sont omniprésentes dans tout
programme Java.

Philémon GLOBLEHI, Développeur Java 117


Gérer l’imprévu : les exceptions

Pourquoi des exceptions ?


Dans un programme, les erreurs sont inévitables : fichier introuvable, division par zéro, connexion
réseau coupée, valeur invalide... Plutôt que de tester manuellement chaque valeur de retour de
chaque méthode, Java utilise les exceptions pour isoler le code de gestion d'erreur du code
métier normal.

Qu'est-ce qu'une exception ?


Une exception est une classe héritant d'Exception qui représente un état anormal. Son nom
doit se terminer par Exception.

Exemples fournis par Java :

●​ NullPointerException : tentative d'utiliser une référence null


●​ NumberFormatException : impossible de convertir une chaîne en nombre
●​ IndexOutOfBoundsException : accès hors limites d'un tableau

Créer votre propre exception

Une exception peut stocker des informations utiles :

Philémon GLOBLEHI, Développeur Java 118


Lancer une exception : throw
Quand vous détectez un problème, jetez une exception avec throw :

Jeter une exception interrompt immédiatement l'exécution de la méthode.

Attraper une exception : try-catch


Pour gérer une exception, utilisez try-catch :

Philémon GLOBLEHI, Développeur Java 119


Le bloc try contient le code susceptible de lancer une exception. Le bloc catch définit
comment réagir si cette exception survient.

Plusieurs catch

Vous pouvez attraper différents types d'exceptions :

Ordre important : Les exceptions les plus spécifiques d'abord, les plus générales ensuite.

Attraper plusieurs types identiquement

Si le traitement est identique pour plusieurs exceptions, utilisez | :

Philémon GLOBLEHI, Développeur Java 120


Propager une exception : throws
Si une méthode peut lancer une exception mais ne la gère pas, elle doit le déclarer avec throws
:

L'exception remonte alors automatiquement à l'appelant, qui devra lui-même la gérer ou la


propager.

Le bloc finally : toujours exécuté


Un bloc finally s'exécute toujours, qu'il y ait eu exception ou non :

Philémon GLOBLEHI, Développeur Java 121


Même si le try contient un return, le finally s'exécute avant la sortie de la méthode.

Try-with-resources : fermer automatiquement


Pour les ressources (fichiers, connexions...), Java offre une syntaxe plus simple :

Le compilateur génère automatiquement un finally qui ferme la ressource. Marche avec tout
type implémentant AutoCloseable ou Closeable.

Plusieurs ressources :

Hiérarchie d'exceptions

Philémon GLOBLEHI, Développeur Java 122


Vous pouvez créer des hiérarchies pour grouper les exceptions :

Ensuite, attraper au niveau souhaité :

Encapsuler une exception : la cause


Une exception peut en encapsuler une autre :

Récupérer la cause :

Philémon GLOBLEHI, Développeur Java 123


Checked vs Unchecked

Checked exceptions (Exception)

Héritent d'Exception (sauf RuntimeException). Le compilateur force leur gestion ou


déclaration.

Utilisez-les pour les erreurs métier que l'application peut gérer (solde insuffisant, fichier
manquant...).

Unchecked exceptions (RuntimeException)

Héritent de RuntimeException ou Error. Pas besoin de les déclarer.

Utilisez-les pour les erreurs techniques ou les bugs (paramètre invalide, état incohérent...).

Exemples fournis par Java :

●​ NullPointerException : référence null


●​ IllegalArgumentException : paramètre invalide

Philémon GLOBLEHI, Développeur Java 124


●​ ArithmeticException : division par zéro
●​ ClassCastException : cast invalide

Error : n'y touchez pas

Error et ses enfants (OutOfMemoryError, StackOverflowError...) signalent des


problèmes graves de la JVM. Ne les créez jamais, ne les attrapez généralement pas.

Polymorphisme et exceptions
Une méthode redéfinie peut :

●​ Ne pas déclarer d'exception (OK)


●​ Déclarer des exceptions plus spécifiques (OK)
●​ Jamais déclarer d'exceptions nouvelles ou plus larges (interdit)

Respecte le principe de substitution de Liskov.

Afficher la pile d'appel


Pour déboguer, affichez la trace complète :

Philémon GLOBLEHI, Développeur Java 125


Ce qu'il faut retenir
Les exceptions séparent le code métier de la gestion d'erreur. Lancez avec throw, attrapez avec
try-catch. Déclarez les checked exceptions avec throws. Utilisez finally ou
try-with-resources pour libérer les ressources. Les checked exceptions (Exception) forcent la
gestion, les unchecked (RuntimeException) signalent des bugs ou erreurs techniques. Ne
créez jamais d'Error. Respectez la hiérarchie dans les catch : du plus spécifique au plus
général. Les exceptions rendent le code plus robuste et lisible qu'un simple retour de code
d'erreur.

Philémon GLOBLEHI, Développeur Java 126


Les énumérations : quand les constantes
deviennent intelligentes

Le problème des constantes


Avant les énumérations, on utilisait des constantes entières pour représenter des ensembles finis
de valeurs :

Problèmes :

●​ Aucun typage réel (n'importe quel int est accepté)


●​ Pas de liste énumérable des valeurs
●​ Comparaisons peu sûres

Les énumérations : la solution


Une énumération définit un type avec un ensemble fini de valeurs possibles :

Convention : noms en majuscules, mots séparés par _.

Philémon GLOBLEHI, Développeur Java 127


Fichier : [Link] (comme une classe).

Utiliser une énumération

Une variable d'énumération peut valoir null.

Énumérations internes
Vous pouvez définir une énumération dans une classe :

Méthodes fournies

Philémon GLOBLEHI, Développeur Java 128


Méthodes de classe

valueOf(String) : convertit une chaîne en énumération

values() : retourne un tableau de tous les éléments

Méthodes d'instance

name() : retourne le nom en chaîne

ordinal() : retourne la position (commence à 0)

compareTo() : compare selon l'ordre de déclaration

Comparer des énumérations

Philémon GLOBLEHI, Développeur Java 129


Utilisez == directement (recommandé) :

Chaque élément d'énumération n'existe qu'une seule fois en mémoire, donc == fonctionne
parfaitement.

Énumérations dans un switch

Pas besoin de préfixer par Priorite., le compilateur comprend.

Ce qui se passe en coulisses


Une énumération est transformée en classe finale par le compilateur :

Philémon GLOBLEHI, Développeur Java 130


Devient (conceptuellement) :

Conséquences :

●​ Les valeurs sont des instances de l'énumération elle-même


●​ Le constructeur est privé (impossible de créer de nouvelles instances)
●​ La classe est finale (impossible d'hériter d'une énumération)
●​ Hérite d'Enum

Ajouter méthodes et attributs


Une énumération peut contenir des méthodes et attributs comme une classe normale :

Philémon GLOBLEHI, Développeur Java 131


Utilisation :

Constructeurs personnalisés
Ajoutez un constructeur (obligatoirement private) pour enrichir chaque élément :

Philémon GLOBLEHI, Développeur Java 132


Utilisation :

Exemple concret

Philémon GLOBLEHI, Développeur Java 133


Ce qu'il faut retenir
Les énumérations créent des types avec un ensemble fini de valeurs. Elles sont plus sûres que
des constantes entières car fortement typées. Utilisez == pour comparer. Les méthodes
values() et valueOf() facilitent la manipulation. Les énumérations peuvent contenir attributs,
méthodes et constructeurs. Elles sont finales et ne peuvent pas être étendues. Chaque valeur
n'existe qu'une fois en mémoire. Utilisez-les pour modéliser des états, des niveaux, des
catégories... tout ensemble fermé et connu à l'avance.

Philémon GLOBLEHI, Développeur Java 134


Les interfaces : des contrats en code

Qu'est-ce qu'une interface ?


Une interface définit un contrat : un ensemble de méthodes qu'une classe s'engage à
implémenter. Elle crée une abstraction pure, sans aucun détail d'implémentation (ou presque).

Les interfaces permettent un découplage maximal : le code client utilise l'interface sans connaître
l'implémentation concrète.

Déclarer une interface

Comme une classe, une interface a :

●​ Une portée (public généralement)


●​ Un nom (dans son propre fichier [Link])
●​ Un bloc de déclaration

Important : Les méthodes d'interface sont public et abstract par défaut. Pas besoin de le
préciser.

Implémenter une interface


Une classe utilise implements pour indiquer qu'elle respecte le contrat :

Philémon GLOBLEHI, Développeur Java 135


Une classe concrète doit implémenter toutes les méthodes de l'interface (sauf si elle est
abstraite).

Plusieurs interfaces
Une classe peut implémenter autant d'interfaces que nécessaire :

Philémon GLOBLEHI, Développeur Java 136


C'est une forme d'héritage multiple, mais sans les problèmes de l'héritage classique.

Utiliser le type interface


L'intérêt principal : manipuler des objets via leur interface, pas leur classe concrète :

Ça permet de changer d'implémentation sans toucher au code client.

Constantes dans les interfaces


Les attributs d'interface sont automatiquement public static final :

Philémon GLOBLEHI, Développeur Java 137


Méthodes static
Les interfaces peuvent avoir des méthodes static avec implémentation :

Appel direct via l'interface :

Héritage d'interfaces

Philémon GLOBLEHI, Développeur Java 138


Une interface peut hériter d'autres interfaces (même plusieurs) :

Une classe implémentant Transactionnel doit implémenter les méthodes de Creditable ET


Debitable.

Interfaces marqueurs
Une interface vide qui sert juste à marquer un type :

Utilisée avec instanceof pour adapter le comportement :

Exemple célèbre : Cloneable en Java.

Philémon GLOBLEHI, Développeur Java 139


Implémentations par défaut (depuis Java 8)
Une interface peut fournir une implémentation par défaut avec default :

Les classes n'ont pas besoin de redéfinir transferer(), mais peuvent le faire si nécessaire.
Utile pour faire évoluer une interface sans casser le code existant.

Attention : À utiliser avec parcimonie. Les interfaces doivent rester principalement des contrats,
pas des classes déguisées.

Ségrégation d'interface
Principe : ne forcez pas un client à dépendre de méthodes qu'il n'utilise pas. Préférez plusieurs
petites interfaces spécialisées qu'une grosse interface fourre-tout.

Philémon GLOBLEHI, Développeur Java 140


Un système de consultation n'a besoin que de Consultation, pas de tout le reste.

Inversion de dépendance
Principe : dépendez d'abstractions (interfaces), pas d'implémentations concrètes.

Philémon GLOBLEHI, Développeur Java 141


Maintenant, Commande fonctionne avec n'importe quelle implémentation de Database (MySQL,
PostgreSQL, fichiers, mémoire...).

Interface vs Classe abstraite


Quand utiliser quoi ?

Interface :

●​ Définir un contrat de comportement


●​ Implémenter plusieurs "rôles" différents
●​ Découpler totalement l'implémentation
●​ Relation "peut faire" ou "se comporte comme"

Classe abstraite :

●​ Mutualiser du code commun


●​ Créer une hiérarchie de types liés
●​ Partager un état (attributs) commun
●​ Relation "est un type de"

Exemple : ArrayList est une AbstractList (héritage) mais se comporte comme une List
(interface).

Ce qu'il faut retenir


Les interfaces définissent des contrats sans imposer d'implémentation. Une classe peut
implémenter plusieurs interfaces (héritage multiple partiel). Les méthodes sont public

Philémon GLOBLEHI, Développeur Java 142


abstract par défaut. Les attributs sont public static final (constantes). Les méthodes
default permettent d'évoluer sans casser le code existant. Préférez plusieurs petites interfaces
spécialisées. L'inversion de dépendance découple le code via les interfaces. Utilisez les
interfaces pour définir "ce qu'un objet peut faire", les classes abstraites pour "ce qu'un objet est".
Les interfaces sont au cœur de la conception d'applications flexibles et évolutives.

Philémon GLOBLEHI, Développeur Java 143


Génériques : écrire du code réutilisable

Le problème sans génériques


Avant les génériques, les collections pouvaient contenir n'importe quel type d'objet, ce qui
causait des erreurs à l'exécution :

Impossible de détecter les erreurs à la compilation. Nécessite des casts partout.

Les génériques : typage à la compilation


Les génériques permettent de spécifier le type contenu dans une collection :

Le compilateur vérifie la cohérence des types. Plus sûr, plus lisible.

Notation en diamant (depuis Java 7)


Évitez la répétition avec <> :

Philémon GLOBLEHI, Développeur Java 144


Le compilateur devine le type à partir de la gauche.

Plusieurs types paramétrés


Certaines classes acceptent plusieurs types génériques :

Le premier type est la clé (String), le second est la valeur (Integer).

Substitution et génériques
Attention piège : même si String hérite d'Object, List<String> n'hérite pas de
List<Object> !

Pourquoi ? Sinon, on pourrait ajouter n'importe quoi :

Types bornés : contrôler la substitution

Borne supérieure : extends

Philémon GLOBLEHI, Développeur Java 145


Pour une liste en lecture seule (consultation) :

? extends CompteBancaire signifie "n'importe quel type qui hérite de CompteBancaire". On


peut lire, mais pas écrire (le compilateur ne connaît pas le type exact).

Borne inférieure : super

Pour une liste en écriture seule (ajout) :

? super CompteEpargne signifie "n'importe quel type parent de CompteEpargne". On peut


écrire, mais pas lire avec le type précis.

Joker sans borne : ?

Aucune information de type :

Très limité, rarement utilisé seul.

Méthodes génériques

Philémon GLOBLEHI, Développeur Java 146


Une méthode peut définir ses propres types paramétrés :

Le <T extends CompteBancaire> avant le type de retour déclare le type générique. La


méthode fonctionne avec n'importe quelle liste de comptes bancaires :

Le compilateur infère T à partir du paramètre passé.

Classes génériques
Une classe entière peut être générique :

Philémon GLOBLEHI, Développeur Java 147


Utilisation :

Avec bornes :

Conventions de nommage
●​ T : type générique général

Philémon GLOBLEHI, Développeur Java 148


●​ E : élément (dans les collections)
●​ K : clé (Key)
●​ V : valeur (Value)
●​ U, V, W : plusieurs types génériques

Limitations importantes
Pas de types primitifs : uniquement des classes

Pas d'instanceof avec type paramétré :

Pas d'instanciation du type générique :

Pas d'attributs static génériques :

Pas de tableaux de types paramétrés :

Philémon GLOBLEHI, Développeur Java 149


Pas de catch avec type générique :

Pas de surcharge juste sur le type paramétré :

Effacement de type (type erasure)


À la compilation, les types génériques sont effacés et remplacés par leur borne (ou Object si
aucune borne) :

Devient en bytecode :

C'est pourquoi les génériques ont ces limitations : le type exact n'existe plus à l'exécution.

Philémon GLOBLEHI, Développeur Java 150


Ce qu'il faut retenir
Les génériques apportent la sécurité du typage à la compilation. Utilisez <Type> pour
paramétrer les collections. ? extends T pour lire, ? super T pour écrire. Les méthodes et
classes peuvent être génériques. Conventions : T, E, K, V. Les types primitifs ne fonctionnent pas,
utilisez les classes enveloppes. L'effacement de type explique les limitations. Les génériques
rendent le code plus sûr et plus expressif sans sacrifier la flexibilité.

Philémon GLOBLEHI, Développeur Java 151


Collections : gérer tes données comme un
pro

Au-delà des tableaux


Les tableaux ont une limite majeure : taille fixe. Impossible d'ajouter ou retirer des éléments. Les
collections du Java Collections Framework (package [Link]) offrent des structures de
données flexibles et puissantes.

Trois grandes familles :

●​ Listes (List) : collections ordonnées, doublons autorisés


●​ Ensembles (Set) : pas de doublons
●​ Tableaux associatifs (Map) : paires clé-valeur

Toutes les collections sont génériques et ne fonctionnent qu'avec des objets (utilisez Integer
au lieu d'int, par exemple).

Les listes (List)

ArrayList : accès rapide

Optimisée pour la lecture par index, moins pour l'insertion/suppression.

Philémon GLOBLEHI, Développeur Java 152


Réserver de l'espace pour optimiser :

LinkedList : insertion/suppression rapides

Liste doublement chaînée, lente pour l'accès aléatoire.

Utilisable aussi comme file ou pile :

Philémon GLOBLEHI, Développeur Java 153


ArrayDeque : files et piles performantes

Plus rapide que LinkedList pour les opérations FIFO/LIFO, mais n'implémente pas List.

PriorityQueue : file avec priorité

Les éléments sortent dans l'ordre naturel (tri automatique).

Interfaces des listes

●​ Iterable : parcours avec for amélioré


●​ Collection : méthodes de base (add, remove, size, toArray...)
●​ List : accès par index, tri
●​ Queue : file (FIFO)

Philémon GLOBLEHI, Développeur Java 154


●​ Deque : file double (FIFO/LIFO)

Principe : Utilisez le type d'interface le plus restrictif adapté à vos besoins.

Les ensembles (Set)


Pas de doublons. Deux éléments sont identiques si [Link](e2) retourne true.

HashSet : rapide, sans ordre

Basé sur le code de hachage (hashCode()). Très performant.

Ordre de parcours imprévisible.

TreeSet : trié automatiquement

Maintient un ordre naturel (les éléments doivent implémenter Comparable ou fournir un


Comparator).

Philémon GLOBLEHI, Développeur Java 155


Moins performant que HashSet pour ajout/suppression.

LinkedHashSet : ordre d'insertion préservé

Compromis entre HashSet (performance) et TreeSet (ordre). Conserve l'ordre d'insertion.

Interfaces des ensembles

●​ Set : ensemble sans doublon


●​ SortedSet : ordre naturel maintenu
●​ NavigableSet : navigation avancée

Les tableaux associatifs (Map)


Associent une clé unique à une valeur.

HashMap : rapide, sans ordre

Basé sur le code de hachage. Très performant.

Philémon GLOBLEHI, Développeur Java 156


Ordre de parcours imprévisible.

TreeMap : clés triées

Maintient les clés dans l'ordre naturel.

LinkedHashMap : ordre d'insertion

Conserve l'ordre d'ajout des clés.

Philémon GLOBLEHI, Développeur Java 157


Interfaces des maps

●​ Map : tableau associatif de base


●​ SortedMap : clés en ordre naturel
●​ NavigableMap : navigation avancée

Convertir collection → tableau

La classe utilitaire Collections


Méthodes statiques pratiques :

Collections vides immutables :

Philémon GLOBLEHI, Développeur Java 158


Ce qu'il faut retenir
Les collections remplacent avantageusement les tableaux pour les besoins courants.
ArrayList pour l'accès rapide, LinkedList pour l'insertion/suppression. HashSet pour des
ensembles performants, TreeSet pour un ordre naturel. HashMap pour des associations
clé-valeur rapides, TreeMap pour des clés triées. Utilisez toujours le type d'interface approprié
(List, Set, Map) plutôt que les classes concrètes. Les collections ne fonctionnent qu'avec des
objets, utilisez les classes enveloppes pour les primitifs. Maîtriser les collections est essentiel en
Java moderne.

Philémon GLOBLEHI, Développeur Java 159


Lire et écrire : les entrées/sorties

Flux de données : le concept de base


En Java, toute opération d'entrée/sortie passe par des flux (streams). Un flux est un canal qui
transporte des données. Quatre classes abstraites fondamentales :

●​ InputStream : lecture de données binaires


●​ OutputStream : écriture de données binaires
●​ Reader : lecture de caractères (texte)
●​ Writer : écriture de caractères (texte)

Flux binaires en lecture : InputStream

ByteArrayInputStream : lire depuis la mémoire

FileInputStream : lire un fichier

Philémon GLOBLEHI, Développeur Java 160


Important : Utilisez try-with-resources pour fermer automatiquement les flux et libérer les
ressources système.

Flux binaires en écriture : OutputStream

FileOutputStream : écrire dans un fichier

Flux de caractères : Reader et Writer

FileReader et FileWriter : fichiers texte

Limitation : encodage par défaut du système, pas configurable.

Décorateurs : ajouter des fonctionnalités


Les décorateurs enrichissent les flux avec des capacités supplémentaires.

BufferedReader/BufferedWriter : zone tampon

Philémon GLOBLEHI, Développeur Java 161


Améliore les performances en regroupant les lectures/écritures :

InputStreamReader/OutputStreamWriter : encodage

Convertit entre flux binaires et caractères avec un encodage spécifié :

Chaîner les décorateurs

Un seul close() sur le décorateur final ferme toute la chaîne.

Philémon GLOBLEHI, Développeur Java 162


La classe Scanner : lecture facilitée
Pour lire et valider des données depuis la console ou un fichier :

Avec validation :

Gestion moderne des fichiers : Path et Files

Path : représenter un chemin

Philémon GLOBLEHI, Développeur Java 163


Files : opérations simplifiées

Files est pratique pour les petits fichiers. Pour les gros fichiers, préférez les flux pour
économiser la mémoire.

Accès réseau : URL et URLConnection

Philémon GLOBLEHI, Développeur Java 164


Même abstraction que pour les fichiers !

Sérialisation : sauvegarder des objets


Convertir des objets en flux binaires et vice-versa.

Rendre une classe sérialisable

Sérialiser (sauvegarder)

Désérialiser (charger)

Philémon GLOBLEHI, Développeur Java 165


Données transient : exclure de la sérialisation

Limites de la sérialisation

●​ Format propre à Java (pas pour échanger avec d'autres langages)


●​ Très dépendant de la structure des classes
●​ Classes doivent être disponibles à la désérialisation
●​ Modifications de classe risquent de casser la compatibilité

Le serialVersionUID permet de gérer les versions de classes. Changez-le quand les


modifications cassent la compatibilité.

Console : [Link], [Link], [Link]


Flux spéciaux ouverts au démarrage de l'application :

●​ [Link] : InputStream de la console (entrée standard)


●​ [Link] : PrintStream de la console (sortie standard)
●​ [Link] : PrintStream pour les erreurs

Ces flux n'ont pas besoin d'être fermés explicitement.

Ce qu'il faut retenir


Les flux (InputStream, OutputStream, Reader, Writer) sont l'abstraction centrale des I/O
en Java. Utilisez try-with-resources pour fermer automatiquement les flux. Les décorateurs
enrichissent les flux (buffer, encodage, comptage...). Path et Files simplifient les opérations sur
fichiers. La sérialisation permet de sauvegarder des objets, mais a des limites. Même API pour
fichiers, mémoire, réseau : c'est la force de l'abstraction Java. Préférez les flux pour les gros
volumes, Files pour les petits fichiers.

Philémon GLOBLEHI, Développeur Java 166


Manipuler le temps : les dates en Java

Historique complexe
Java a connu plusieurs générations d'API pour les dates, créant une situation confuse avec trois
approches coexistantes.

Date : l'ancêtre obsolète


La classe [Link] est la première API, aujourd'hui largement dépréciée.

Limitations majeures :

●​ Pas de dates avant 1900


●​ Pas de fuseaux horaires
●​ Calendrier grégorien uniquement
●​ Pas d'opérations (ajouter des jours, etc.)

Pourtant, elle reste utilisée pour des raisons de compatibilité (notamment avec SQL et certaines
bibliothèques).

Construire une Date à partir de millisecondes depuis l'epoch (1er janvier 1970) :

Philémon GLOBLEHI, Développeur Java 167


Calendar : l'amélioration partielle
Introduit en Java 1.1 pour remplacer Date, mais restant fastidieux à utiliser.

Avantages :

●​ Toutes les dates possibles (même avant notre ère)


●​ Support des fuseaux horaires
●​ Opérations sur les dates

Limitations :

●​ API lourde et complexe


●​ Classe abstraite (pas de new Calendar())
●​ Pas de notion de durée

L'API Date/Time moderne (Java 8+)

Philémon GLOBLEHI, Développeur Java 168


Depuis Java 8, l'API [Link] est la solution recommandée. Toutes les classes sont
immutables et thread-safe.

Dates locales (sans fuseau horaire)

LocalDate : uniquement une date

LocalTime : uniquement une heure

LocalDateTime : date et heure

Conversion entre types :

Avec fuseaux horaires :

Philémon GLOBLEHI, Développeur Java 169


Pour des dates avec fuseau horaire : utilisez ZonedDateTime.

Années et mois

Year et YearMonth pour manipulations avancées :

Instant : point dans le temps

Pour les traitements informatiques (horodatage, mesures) :

Périodes et durées

Period : différence en années/mois/jours

Philémon GLOBLEHI, Développeur Java 170


Duration : différence en heures/minutes/secondes

Formatage des dates

DateTimeFormatter pour afficher les dates :

Lecture (parsing) de dates

Convertir une chaîne en date :

Philémon GLOBLEHI, Développeur Java 171


Codes de format courants
●​ dd : jour sur 2 chiffres
●​ MM : mois sur 2 chiffres
●​ yyyy : année sur 4 chiffres
●​ HH : heure (24h) sur 2 chiffres
●​ mm : minutes sur 2 chiffres
●​ ss : secondes sur 2 chiffres
●​ MMMM : nom du mois en lettres

Exemple : calculer un âge

Ce qu'il faut retenir


Utilisez toujours l'API [Link] (Java 8+) pour du nouveau code. LocalDate, LocalTime,
LocalDateTime pour les dates sans fuseau. Instant pour les horodatages techniques.
Period pour durées en jours/mois/ans, Duration pour heures/minutes/secondes.
DateTimeFormatter pour formater et parser. Toutes les classes sont immutables et
thread-safe. Évitez Date et Calendar sauf obligation de compatibilité. L'API moderne est plus
simple, plus puissante et plus sûre.

Philémon GLOBLEHI, Développeur Java 172


Penser fonctionnel : lambas et streams

La programmation fonctionnelle en Java


Depuis Java 8, le langage intègre des éléments de programmation fonctionnelle, un paradigme
basé sur l'appel et la composition de fonctions.

Avantages :

●​ Fonctions comme entités de première classe (passables en paramètre)


●​ Code plus concis et lisible
●​ Moins de structures de contrôle imbriquées (if, for)
●​ Traitement découpé en processus simples

Limitation : Java ne supporte pas nativement les fonctions. Les lambdas sont un "sucre
syntaxique" qui cache en réalité des interfaces.

Les lambdas : fonctions anonymes


Une lambda est une fonction sans nom, déclarée à la volée.

Syntaxe
(paramètres) -> { corps }

Simplifications possibles :

●​ Parenthèses optionnelles si un seul paramètre


●​ Types inférés par le compilateur
●​ Accolades optionnelles si une seule instruction
●​ return implicite si une seule expression

Exemples

Somme de deux nombres :

Philémon GLOBLEHI, Développeur Java 173


Affichage :

Constante :

Utilisation pratique

Trier une liste avec un critère personnalisé :

Appliquer une action sur chaque élément :

Comparé au style impératif classique :

Philémon GLOBLEHI, Développeur Java 174


Closures : capturer l'environnement
Une lambda capture les variables de son contexte (closure).

Restriction : Les variables capturées sont implicitement final (non modifiables).

Interfaces fonctionnelles
Une interface fonctionnelle ne déclare qu'une seule méthode abstraite. Elle peut être
implémentée par une lambda.

Créer une interface fonctionnelle

Philémon GLOBLEHI, Développeur Java 175


L'annotation @FunctionalInterface force la vérification par le compilateur.

Utiliser avec une lambda

Passer en paramètre

Interfaces fonctionnelles standards : [Link]


Le JDK fournit des interfaces prêtes à l'emploi :

Function : transformation

Prend un paramètre, retourne un résultat.

Philémon GLOBLEHI, Développeur Java 176


Operator : opération sur même type

Prend un ou plusieurs paramètres du même type, retourne le même type.

Consumer : consommateur

Prend un paramètre, ne retourne rien.

Supplier : fournisseur

Aucun paramètre, retourne un résultat.

Predicate : test booléen

Prend un paramètre, retourne un booléen.

Philémon GLOBLEHI, Développeur Java 177


Références de méthodes : l'opérateur ::
Alternative plus lisible aux lambdas quand une méthode existe déjà.

Référence de méthode statique

Équivalent à : s -> [Link]()

Référence de méthode d'instance

Équivalent à : e -> [Link](e)

Référence de constructeur

Avec paramètres :

La classe Optional : gérer l'absence de valeur

Philémon GLOBLEHI, Développeur Java 178


Alternative à null pour représenter une valeur potentiellement absente.

Création

Style impératif (à éviter)

Style fonctionnel (recommandé)

Chaînage :

Philémon GLOBLEHI, Développeur Java 179


Exemple complet : régulateur de vitesse

Utilisation :

Ce qu'il faut retenir


Les lambdas sont des fonctions anonymes : (params) -> expression. Une interface
fonctionnelle n'a qu'une seule méthode abstraite et peut être implémentée par une lambda.
[Link] fournit les interfaces courantes (Function, Consumer, Supplier,

Philémon GLOBLEHI, Développeur Java 180


Predicate). L'opérateur :: référence des méthodes existantes pour plus de lisibilité. Les
lambdas capturent leur environnement (closure), mais ne peuvent modifier les variables
capturées. Optional remplace null dans un style fonctionnel. La programmation fonctionnelle
favorise la composition, réduit les structures de contrôle et améliore la lisibilité. C'est un
changement de paradigme qui rend Java plus expressif et concis.

Philémon GLOBLEHI, Développeur Java 181


Les Streams : traiter les données en flux

Qu'est-ce qu'un stream ?


Un stream (flux) est une séquence d'éléments sur laquelle on applique des opérations de
manière fonctionnelle, introduit en Java 8.

Avantages majeurs :

●​ Traiter des séquences sans boucles explicites


●​ Code plus lisible et concis
●​ Traitement en flux : faible empreinte mémoire
●​ Parallélisation facile pour exploiter les multicœurs

Important : Un stream ne stocke pas les données, il les traite à la volée.

Créer des streams

Depuis un builder

Streams de primitifs

Les valeurs ne créent pas tous les nombres en mémoire, c'est un flux !

Philémon GLOBLEHI, Développeur Java 182


Stream infini

Depuis un tableau

Depuis une collection

Depuis un fichier

Opérations de base : forEach


Exécuter une action sur chaque élément :

Réduction : obtenir un résultat unique

Opérations mathématiques

Philémon GLOBLEHI, Développeur Java 183


Réduction personnalisée

Collecte : créer une nouvelle collection

Vers une liste

Philémon GLOBLEHI, Développeur Java 184


Vers un ensemble (Set)

Grouper par critère (Map)

Joindre en chaîne

Filtrage : éliminer des éléments

Philémon GLOBLEHI, Développeur Java 185


Chaîner les filtres :

Avec limite :

Mapping : transformer les éléments


Changer le type ou la valeur des éléments :

Philémon GLOBLEHI, Développeur Java 186


Vers types primitifs :

Enchaînement d'opérations
La puissance des streams vient du chaînage :

Philémon GLOBLEHI, Développeur Java 187


Parallélisme : exploiter les multicœurs
Exécuter en parallèle sur plusieurs processeurs :

Attention : Les opérations doivent être indépendantes de l'ordre.

Autres opérations utiles

distinct : supprimer les doublons

Philémon GLOBLEHI, Développeur Java 188


sorted : trier

skip et limit : pagination

anyMatch, allMatch, noneMatch

Exemples pratiques

Philémon GLOBLEHI, Développeur Java 189


Compter les lettres dans une chaîne

Lire et traiter un fichier CSV

Philémon GLOBLEHI, Développeur Java 190


Ce qu'il faut retenir
Les streams traitent des séquences sans boucles explicites. Créez-les depuis collections,
tableaux, plages, fichiers. Les opérations intermédiaires (filter, map, sorted) se chaînent. Les
opérations terminales (collect, forEach, reduce) produisent le résultat. Les streams sont
paresseux : rien ne s'exécute tant qu'il n'y a pas d'opération terminale. parallelStream()
active le traitement parallèle. Les streams limitent l'empreinte mémoire en traitant à la volée.
Combinez filter, map, collect pour des traitements puissants et lisibles. Les streams
incarnent la programmation fonctionnelle en Java.

Philémon GLOBLEHI, Développeur Java 191


Les classes internes : déclarer des classes
dans des classes

Qu'est-ce qu'une classe interne ?


Une classe interne (inner class) est déclarée à l'intérieur d'une autre classe, plutôt que dans son
propre fichier.

Trois types principaux : classes internes statiques, classes internes, classes anonymes.

Classes internes statiques


Déclarées avec static, elles appartiennent à l'espace de noms de la classe englobante.

Caractéristiques

●​ Nom complet inclut la classe englobante : [Link]


●​ Partage l'espace privé avec la classe englobante (accès mutuel aux membres privés)
●​ N'a accès qu'aux membres statiques de la classe englobante
●​ Sert à regrouper des petites classes utilitaires

Philémon GLOBLEHI, Développeur Java 192


Exemple pratique : Comparateur

Utilisation :

Notez que Comparateur peut accéder aux champs privés nom et prenom des objets
Personne.

Philémon GLOBLEHI, Développeur Java 193


Classes internes (non statiques)
Sans static, elles maintiennent une référence vers l'instance englobante.

Caractéristiques

●​ Ne peuvent être créées que depuis une instance de la classe englobante


●​ Ont accès à tous les membres (même non statiques) de l'instance englobante
●​ Créent un couplage fort entre les deux objets
●​ Couramment utilisées pour les interfaces graphiques

Exemple : Interface graphique

Philémon GLOBLEHI, Développeur Java 194


Les classes ActionIncrementer et ActionDecrementer ont accès aux méthodes privées et
attributs de l'instance Compteur qui les a créées.

Classes anonymes
Classe sans nom, déclarée et instanciée en une seule fois.

Philémon GLOBLEHI, Développeur Java 195


Syntaxe

Exemple : Logger

Philémon GLOBLEHI, Développeur Java 196


Utilisation :

Capture de variables

Philémon GLOBLEHI, Développeur Java 197


Les classes anonymes capturent les variables et paramètres locaux, mais ne peuvent pas les
modifier.

Avant Java 8, final était obligatoire. Maintenant c'est implicite ("effectively final").

Limitations

●​ Pas de constructeur (la classe n'a pas de nom)


●​ Ne peut étendre qu'une classe avec constructeur sans paramètre
●​ Pas de variables de type "classe anonyme"

Accès à la classe englobante : [Link]


Quand il y a collision de noms, référencez explicitement la classe englobante :

Philémon GLOBLEHI, Développeur Java 198


Classe locale (dans une méthode)
Déclarer une classe à l'intérieur d'une méthode :

Avantages sur classe anonyme :

●​ Possibilité de déclarer des constructeurs


●​ Nom explicite (meilleur pour le débogage)

Portée : uniquement visible dans la méthode.

Interfaces et énumérations internes


Possibles et toujours implicitement static :

Philémon GLOBLEHI, Développeur Java 199


Utilisation :

Quand utiliser quoi ?


Classe interne statique :

●​ Petite classe utilitaire liée conceptuellement à la classe englobante


●​ Pas besoin d'accès aux instances de la classe englobante

Classe interne (non statique) :

●​ Couplage fort avec une instance de la classe englobante


●​ Besoin d'accéder aux membres non statiques
●​ Interfaces graphiques, listeners, callbacks

Classe anonyme :

●​ Implémentation unique et simple d'une interface


●​ Code court (quelques lignes)
●​ Depuis Java 8, souvent remplacée par des lambdas

Classe locale :

Philémon GLOBLEHI, Développeur Java 200


●​ Implémentation plus complexe qu'une lambda
●​ Besoin d'un nom explicite ou de constructeurs
●​ Pas réutilisée ailleurs

Ce qu'il faut retenir


Les classes internes organisent le code en regroupant des classes liées. Les classes internes
statiques n'ont pas de lien avec une instance englobante. Les classes internes (non statiques)
maintiennent une référence vers l'instance qui les a créées. Les classes anonymes sont pratiques
pour des implémentations uniques. Les variables capturées sont implicitement final.
[Link] référence l'instance englobante. Depuis Java 8, préférez les
lambdas aux classes anonymes pour les interfaces fonctionnelles. Les classes internes partagent
l'espace privé avec leur classe englobante.

Philémon GLOBLEHI, Développeur Java 201


Les nouveautés de Java 11 à Java 25

Introduction
Java a beaucoup évolué depuis la version 8. Avec un rythme de release semestriel depuis Java
9, le langage s'enrichit régulièrement de nouvelles fonctionnalités qui le rendent plus moderne,
plus concis et plus performant. Dans cette section, on va explorer ensemble les ajouts les plus
marquants de Java 11 à Java 25.

Pas de panique si vous débutez : ces fonctionnalités sont des extensions de ce que vous
connaissez déjà. Vous n'êtes pas obligé de toutes les maîtriser immédiatement. L'objectif est de
vous donner un aperçu de ce qui existe, pour que vous sachiez où chercher quand vous en
aurez besoin.

Java 11 (LTS - 2018)


Java 11 est une version Long Term Support, encore largement utilisée en production aujourd'hui.

var dans les lambdas

Depuis Java 10, var permet l'inférence de type pour les variables locales. Java 11 l'étend aux
paramètres des lambdas :

Pourquoi c'est utile ? Ça permet d'ajouter des annotations aux paramètres lambda sans répéter
le type :

Philémon GLOBLEHI, Développeur Java 202


Méthodes enrichies pour String

Java 11 ajoute des méthodes pratiques à la classe String :

En pratique : Ces méthodes simplifient énormément le traitement de texte et évitent des


bibliothèques externes.

Exécution directe de fichiers source

Vous pouvez maintenant lancer un fichier .java directement sans compilation préalable :

Philémon GLOBLEHI, Développeur Java 203


Limitation : Ne marche que pour un fichier unique. Parfait pour des scripts ou du prototypage
rapide.

Client HTTP moderne

L'ancien HttpURLConnection était verbeux et peu pratique. Java 11 introduit un client HTTP
moderne dans [Link] :

Philémon GLOBLEHI, Développeur Java 204


Version asynchrone :

Avantages : Support HTTP/2, requêtes asynchrones, API fluide et moderne.

Java 12-13 (2019)

Switch expressions (preview en 12, finalisé en 14)

Le switch devient une expression qui peut retourner une valeur :

Avec des blocs de code :

Philémon GLOBLEHI, Développeur Java 205


Bénéfices : Plus concis, pas de break oubliés, exhaustivité vérifiée par le compilateur.

Blocs de texte (preview en 13, finalisé en 15)

Fini les chaînes avec \n partout ! Les blocs de texte utilisent des triples guillemets :

Requêtes SQL :

Philémon GLOBLEHI, Développeur Java 206


Important : L'indentation est automatiquement gérée. Le compilateur retire l'indentation
commune.

Java 14 (2020)

Records (preview en 14, finalisé en 16)

Les records sont des classes de données immuables ultra-concises. Parfait pour les DTOs, les
objets valeur, etc.

Philémon GLOBLEHI, Développeur Java 207


Le compilateur génère automatiquement :

●​ Constructeur avec tous les paramètres


●​ Getters (sans le préfixe get)
●​ equals(), hashCode(), toString()
●​ Tous les champs sont final

Utilisation :

Philémon GLOBLEHI, Développeur Java 208


Vous pouvez ajouter des méthodes :

Quand utiliser ? Pour toute classe qui sert uniquement à transporter des données immuables.

Pattern matching pour instanceof (preview en 14, finalisé en 16)

Fini les casts redondants après un instanceof :

Philémon GLOBLEHI, Développeur Java 209


La variable s est automatiquement créée et disponible dans le bloc if.

Exemple plus complexe :

Java 17 (LTS - 2021)


Java 17 est la version LTS actuelle, celle recommandée pour la production.

Sealed classes (finalisé)

Les sealed classes contrôlent finement qui peut hériter d'une classe ou implémenter une
interface :

Philémon GLOBLEHI, Développeur Java 210


Pourquoi c'est utile ?

1.​ Exhaustivité garantie : Le compilateur peut vérifier que tous les cas sont traités
2.​ Domaine fermé : Parfait pour modéliser des types finis (états, événements, etc.)
3.​ Sécurité : Empêche l'extension non contrôlée de votre hiérarchie

Philémon GLOBLEHI, Développeur Java 211


Avec le pattern matching (preview) :

Pattern matching pour switch (preview)

Extension du pattern matching au switch :

Avec des gardes (conditions supplémentaires) :

Java 19-21 (2022-2023)

Philémon GLOBLEHI, Développeur Java 212


Virtual Threads (Project Loom - finalisé en Java 21)

La révolution de la concurrence en Java !

Les threads classiques sont lourds (1 Mo de stack par thread). Les virtual threads sont ultra-légers
(quelques Ko), permettant d'en créer des millions.

Exemple avec des milliers de threads :

Philémon GLOBLEHI, Développeur Java 213


Cas d'usage typique : Serveurs web avec beaucoup de requêtes simultanées :

Avantages :

●​ Simplification du code (style synchrone, pas de callbacks)


●​ Scalabilité énorme (millions de threads)
●​ Pas besoin de pools de threads complexes

Record Patterns (finalisé en Java 21)

Déconstruire les records directement dans les patterns :

Philémon GLOBLEHI, Développeur Java 214


Dans un switch :

Patterns imbriqués :

Philémon GLOBLEHI, Développeur Java 215


Sequenced Collections (Java 21)

Nouvelles interfaces pour manipuler les collections ordonnées :

Bénéfice : API cohérente pour manipuler le début et la fin des collections ordonnées.

Java 22-23 (2024)

Unnamed Variables and Patterns (Java 22)

Philémon GLOBLEHI, Développeur Java 216


Utilisez _ pour ignorer des valeurs dont vous n'avez pas besoin :

Avant Java 22, vous deviez inventer des noms pour des variables inutilisées :

String Templates (preview en Java 21-23)

Interpolation de chaînes sécurisée (attention, encore en preview) :

Philémon GLOBLEHI, Développeur Java 217


Note : Cette fonctionnalité est encore en preview et sa syntaxe peut changer.

Markdown dans Javadoc (Java 23)

Vous pouvez maintenant écrire de la documentation en Markdown plutôt qu'en HTML :

Philémon GLOBLEHI, Développeur Java 218


Avantage : Documentation plus lisible dans le code source, génération HTML automatique.

Java 24-25 (2025)

Flexible Constructor Bodies (2nd preview en Java 24)

Possibilité d'exécuter du code avant l'appel à super() ou this() :

Préparation de paramètres :

Stream Gatherers (Java 24)

Philémon GLOBLEHI, Développeur Java 219


Nouvelles opérations intermédiaires pour les streams :

Créer un gatherer personnalisé :

Philémon GLOBLEHI, Développeur Java 220


Primitive Types in Patterns (preview Java 23-24)

Pattern matching avec les types primitifs :

Dans les records :

Module Import Declarations (Java 23)

Philémon GLOBLEHI, Développeur Java 221


Simplification des imports pour les modules :

Attention : Utilisez avec parcimonie, car ça peut rendre moins clair d'où viennent les classes.

Améliorations de performance (Java 11-25)

Garbage Collectors

Java a considérablement amélioré ses ramasse-miettes :

ZGC (depuis Java 15) :

●​ Pauses < 10ms même avec des heaps de plusieurs téraoctets


●​ Idéal pour applications nécessitant une faible latence

bash

java -XX:+UseZGC -Xmx16g MonApplication

Shenandoah GC (depuis Java 12) :

●​ Concurrent, faibles pauses

Philémon GLOBLEHI, Développeur Java 222


●​ Alternative à ZGC

bash

java -XX:+UseShenandoahGC -Xmx8g MonApplication

G1GC amélioré :

●​ GC par défaut depuis Java 9


●​ Constamment optimisé dans chaque version

Optimisations du JIT

Chaque version améliore le compilateur Just-In-Time :

●​ Meilleures optimisations des lambdas et streams


●​ Inlining plus agressif
●​ Vectorisation automatique

Philémon GLOBLEHI, Développeur Java 223


Conclusion
Vous voilà arrivé au terme de ce parcours à travers les fondamentaux de Java. De la
manipulation des chaînes de caractères aux streams en passant par les exceptions, les
collections et la programmation fonctionnelle, vous avez parcouru les mécanismes essentiels qui
font de Java un langage robuste et expressif.

Ce que vous maîtrisez maintenant


Vous savez désormais manipuler les chaînes de caractères avec l'immutabilité et les expressions
régulières, gérer proprement les erreurs avec les exceptions checked et unchecked, créer des
types fiables avec les énumérations, définir des contrats avec les interfaces et pratiquer
l'inversion de dépendance.

Les génériques vous permettent d'écrire du code type-safe et réutilisable, tandis que les
collections (listes, ensembles, maps) vous donnent les structures de données adaptées à chaque
besoin. Vous comprenez l'importance de choisir ArrayList ou LinkedList, HashSet ou
TreeSet selon les performances recherchées.

Les entrées/sorties et la gestion des dates n'ont plus de secrets pour vous. Vous savez
manipuler des flux, lire et écrire des fichiers, sérialiser des objets et travailler avec l'API moderne
[Link].

Enfin, la programmation fonctionnelle avec les lambdas, les références de méthodes et les
streams vous ouvre la voie vers un style de code plus déclaratif, concis et souvent plus lisible.
Les classes internes vous permettent d'organiser votre code de manière élégante.

Au-delà de ce guide
Ce guide couvre les fondamentaux, mais Java est un écosystème vaste. Vous pourrez
approfondir les frameworks (Spring, Jakarta EE), la programmation concurrente, les design
patterns, les tests unitaires, ou encore les outils de build (Maven, Gradle).

Philémon GLOBLEHI, Développeur Java 224


L'essentiel à retenir
Java privilégie la clarté et la robustesse. Écrivez du code simple avant de chercher la
sophistication. Utilisez les interfaces pour découpler, les génériques pour la sécurité des types,
les streams pour la lisibilité. Gérez toujours proprement les ressources avec try-with-resources.
Préférez l'immutabilité quand c'est possible. Et surtout, lisez le code des autres : c'est en
explorant des projets open source que vous progresserez le plus.

La programmation est un artisanat qui s'affine avec la pratique. Chaque ligne de code écrite,
chaque erreur corrigée, chaque refactoring réalisé vous rend meilleur. Ne cherchez pas la
perfection immédiate : cherchez d'abord à comprendre, puis à améliorer progressivement.

Bon code !

Philémon GLOBLEHI, Développeur Java 225

Vous aimerez peut-être aussi