Java Avancé Pr. F. TOUFIK 2022/2023 Java Avancé Introduction Rappel • Java est un langage de programmation orienté objet de haut niveau, basé sur des classes. • Développé et publié par Sun Microsystems en 1995. • Actuellement Java appartient à Oracle. • Java s'exécute sur diverses plates-formes, telles que Windows, Mac OS et les différentes versions d'UNIX. • Java est utilisé pour développer des applications mobiles, des applications Web, des applications Desktop, …. • Java est un langage de programmation permet aux programmeurs de write once, run anywhere (WORA). • Cela signifie que le code Java compilé peut s'exécuter sur toutes les plates-formes prenant en charge Java sans qu'il soit nécessaire de le recompiler. F. TOUFIK 2 Java Avancé Introduction Rappel • Java est un langage: • Orienté objet: En Java, tout est un objet. Java peut être facilement étendu car il est basé sur le modèle Objet. • Indépendant de la plate-forme: Contrairement à de nombreux autres langages de programmation, notamment C et C ++, lorsque Java est compilé, il n'est pas compilé dans une machine spécifique à la plate-forme, mais plutôt dans un code binaire indépendant de la plate-forme. Ce code binaire (bytecode) est interprété par la machine virtuelle (JVM) sur la plate-forme sur laquelle il est exécuté. • Simple: Java est conçu pour être facile à apprendre. Si vous comprenez le concept de base de la POO, il serait facile à maîtriser. • Architecture-neutre: Le compilateur Java génère un format de fichier objet indépendant de l'architecture, ce qui rend le code compilé exécutable sur de nombreux processeurs, avec la présence du Java Runtime System. F. TOUFIK 3 Java Avancé Introduction Rappel • Java est un langage: • Multithread: Avec la fonctionnalité multithread de Java, il est possible d'écrire des programmes capables d'effectuer plusieurs tâches simultanément. Cette fonctionnalité permet aux développeurs de créer des applications interactives qui peuvent fonctionner sans problème. • Interprété: Le code binaire Java est traduit en instructions machine natives. Le processus de développement est plus rapide. F. TOUFIK • Performant: Avec l'utilisation de compilateurs Just-In-Time, Java permet des performances élevées. • Distribué: Java est conçu pour l'environnement distribué d'Internet. 4 Java Avancé POO • Rappel En tant que langage doté de l’orientée objet, Java prend en charge les concepts fondamentaux suivants: o Classes o Objets o Méthodes o Encapsulation o Héritage o Polymorphisme o Abstraction F. TOUFIK 5 Java Avancé POO • Rappel Objet: un objet est une structure définie par un état et un comportement. • Exemple : Une voiture a des états: couleur, marque, … ainsi que des comportements: démarrer, ralentir, freiner,… . • • Un objet est une instance d'une classe. Classe: Une classe peut être définie comme un modèle/plan directeur qui décrit le comportement/l'état que l'objet de son type prend en charge. • F. TOUFIK Une classe peut contenir plusieurs type de variables: • Les variables locales. • Les variables d’instance. • Les variables de Classe. 6 Java Avancé Les variables • Rappel Les variables locales • Les variables définies à l'intérieur des méthodes, des constructeurs ou des blocs sont appelées variables locales. La variable sera déclarée et initialisée dans la méthode et la variable sera détruite lorsque la méthode sera terminée. • Les variables d’instance • Les variables d'instance sont des variables au sein d'une classe mais en dehors de toute méthode. Ces variables sont initialisées lors de l'instanciation. Les variables d'instance sont accessibles depuis n'importe quelle méthode, constructeur ou bloc de cette classe. • Les variables de classe • Les variables de classe sont des variables déclarées dans une classe, en dehors de toute méthode, avec le mot-clé static. F. TOUFIK 7 Java Avancé Les constructeurs Rappel • Les constructeurs • Un constructeur initialise un objet lors de sa création. Elle porte le même nom que sa classe et est syntaxiquement similaire à une méthode. Cependant, les constructeurs n'ont pas de type de retour explicite. • En règle générale, on utilise un constructeur pour donner des valeurs initiales aux variables d'instance définies par la classe ou pour effectuer toute autre procédure de démarrage requise pour créer un objet entièrement formé. • Toutes les classes ont des constructeurs. Java fournit automatiquement un constructeur par défaut qui initialise toutes les variables membres à (zéro, null, ‘’’’). Cependant, une fois on définit notre propre constructeur, le constructeur par défaut n'est plus utilisé. F. TOUFIK 8 Java Avancé Les modificateurs Rappel • Les modificateurs • • Java a une grande variété de modificateurs, y compris les suivants: • Les modificateurs de contrôle d’accès. • Les modificateurs sans accès. Pour utiliser un modificateur, on ajoute son mot-clé dans la définition d'une classe, d'une méthode ou d'une variable. Le modificateur précède le reste de l'instruction, comme dans l'exemple suivant. F. TOUFIK 9 Java Avancé Les modificateurs Rappel • Les modificateurs de contrôle d’accès • Java fournit un certain nombre de modificateurs d'accès pour définir les niveaux d'accès pour les classes, les variables, les méthodes et les constructeurs. Les quatre niveaux d'accès sont: F. TOUFIK • Visible par le package (valeur par défaut). Aucun modificateur n'est nécessaire. • Visible uniquement à la classe (private). • Visible par toutes les entités (public). • Visible par le package et toutes les sous-classes (protected). 10 Java Avancé Les modificateurs Rappel • Les modificateurs sans accès • Java fournit un certain nombre de modificateurs sans accès pour obtenir de nombreuses autres fonctionnalités comme: F. TOUFIK • static pour créer des méthodes et des variables de classe. • final pour finaliser les implémentations des classes, des méthodes et des variables. • abstract pour créer des classes et des méthodes abstraites. • Les modificateurs synchronized et volatile, qui sont utilisés pour les threads. 11 Java Avancé Encapsulation • Rappel L'encapsulation en Java est le mécanisme d‘envelopper les données (variables) et le code agissant sur les données (méthodes) en une seule unité. • Dans l'encapsulation, les variables d'une classe seront cachées des autres classes et ne seront accessibles que par les méthodes de leur classe actuelle. Par conséquent, il est également connu sous le nom de masquage de données (data hiding). • Pour réaliser l'encapsulation en Java: • Déclarez les variables d'une classe comme privées (private). • Ajoutez des méthodes setter et getter publiques (public) pour modifier et afficher les valeurs des variables. F. TOUFIK 12 Java Avancé Héritage • Rappel L'héritage peut être défini comme le processus par lequel une classe acquiert les propriétés (méthodes et champs) d'une autre. • Avec l'utilisation de l'héritage, les informations sont rendues gérables dans un ordre hiérarchique. • extends est le mot clé utilisé pour hériter des propriétés d'une classe. • Voici un exemple démontrant l'héritage Java. Dans cet exemple, vous pouvez observer deux classes, à savoir Personne et Etudiant. • En utilisant le mot clé extends, Etudiant hérite la méthodes calculerAge() et afficherInfo() de la classe Personne. • Dans le programme donné, lorsqu'un objet de la classe Etudiant est créé, une copie du contenu de la superclasse est faite à l'intérieur de celui-ci. C'est pourquoi, en utilisant l'objet de la sous-classe, vous pouvez accéder aux membres d'une super-classe. F. TOUFIK 13 Java Avancé Héritage • Rappel La variable de référence super-class peut contenir l'objet de sous-classe, mais en utilisant cette variable, vous ne pouvez accéder qu'aux membres de la superclasse, donc pour accéder aux membres des deux classes, il est recommandé de toujours créer une variable de référence à la sousclasse. • Une sous-classe hérite de tous les membres (champs, méthodes) de sa super-classe. Les constructeurs ne sont pas des membres, ils ne sont donc pas hérités par les sous-classes, mais le constructeur de la super-classe peut être appelé à partir de la sous-classe. • Le mot-clé super est utilisé pour: • Différencier les membres de la super-classe des membres de la sous-classe, s'ils ont les mêmes noms. • F. TOUFIK Invoquer le constructeur de la super-classe à partir de la sous-classe. 14 Java Avancé Abstraction Rappel • Selon le dictionnaire, l'abstraction est la qualité de traiter des idées plutôt que des événements. • Prenant le cas de l’e-mail, des détails complexes tels que ce qui se passe dès que vous envoyez un e-mail, comme le protocole utilisé par votre serveur de messagerie sont cachés à l'utilisateur. • Par conséquent, pour envoyer un e-mail, il vous suffit de saisir le contenu, de mentionner l'adresse du destinataire et de cliquer sur envoyer. • De même dans la programmation orientée objet, l'abstraction est un processus de masquage des détails d'implémentation à l'utilisateur, seule la fonctionnalité sera fournie à l'utilisateur. En d'autres termes, l'utilisateur aura les informations sur ce que fait l'objet au lieu de savoir comment il le fait. • F. TOUFIK En Java, l'abstraction est réalisée à l'aide de classes abstraites et d'interfaces. 15 Java Avancé Abstraction Rappel • Classe Abstraite • Une classe qui contient le mot-clé abstract dans sa déclaration est appelée classe abstraite. • Les classes abstraites peuvent contenir des méthodes abstraites, c'est-à-dire des méthodes sans définition ( public void get(); ) • Mais, si une classe a au moins une méthode abstraite, alors la classe doit être déclarée abstraite. • Si une classe est déclarée abstraite, elle ne peut pas être instanciée. • Si vous héritez d'une classe abstraite, vous devez fournir des implémentations à toutes les méthodes abstraites qu'elle contient. F. TOUFIK 16 Java Avancé Interfaces • Rappel Une interface est similaire à une classe. C'est une collection de méthodes abstraites. Une classe implémente une interface, automatiquement elle hérite les méthodes abstraites de l'interface. • Outre les méthodes abstraites, une interface peut également contenir des constantes, des méthodes par défaut, des méthodes statiques et des types imbriqués. Les corps de méthode existent uniquement pour les méthodes par défaut et les méthodes statiques. • Sauf si la classe qui implémente l'interface est abstraite, toutes les méthodes de l'interface doivent être définies dans la classe. F. TOUFIK 17 Java Avancé Interfaces • F. TOUFIK Rappel Une interface est différente d'une classe de plusieurs manières, notamment: • Vous ne pouvez pas instancier une interface. • Une interface ne contient aucun constructeur. • Toutes les méthodes d'une interface sont abstraites. • Une interface ne peut pas contenir de champs d'instance. • Les seuls champs pouvant apparaître dans une interface doivent être déclarés à la fois static et final. • Une interface n'est pas étendue par une classe ; il est implémenté par une classe. • Une interface peut étendre plusieurs interfaces. 18 Java Avancé Interfaces Rappel • Le mot clé interface est utilisé pour déclarer une interface. • Une interface est implicitement abstraite. • Vous n'avez pas besoin d'utiliser le mot clé abstract lors de la déclaration d'une interface. • Chaque méthode d'une interface est aussi implicitement abstraite, de sorte que le mot-clé abstract n'est pas nécessaire. • Les méthodes d'une interface sont implicitement publiques. • Lorsqu'une classe implémente une interface, vous pouvez considérer la classe comme signant un contrat, acceptant d'exécuter les comportements spécifiques de l'interface. Si une classe n'exécute pas tous les comportements de l'interface, la classe doit se être abstraite. F. TOUFIK 19 Java Avancé Interfaces • Rappel Pour implémenter une interface, on utilise le mot clé implements. • Lors du surcharge des méthodes définies dans les interfaces, il y a plusieurs règles à suivre: • La signature de la méthode d'interface et le même type ou sous-type de retour doivent être conservés lors de la redéfinition des méthodes. • Une classe d'implémentation elle-même peut être abstraite et si c'est le cas, les méthodes d'interface n'ont pas besoin d'être implémentées. • Lors de l'implémentation des interfaces, il existe plusieurs règles: • Une classe peut implémenter plusieurs interfaces à la fois. • Une classe ne peut étendre qu'une seule classe, mais implémenter de nombreuses interfaces. • Une interface peut étendre une autre interface, de la même manière qu'une classe peut étendre une autre classe. F. TOUFIK 20 Java Avancé Polymorphisme • Rappel Le polymorphisme est la capacité d'un objet à prendre plusieurs formes. L'utilisation la plus courante du polymorphisme dans la POO se produit lorsqu'une référence de classe parent est utilisée pour faire référence à un objet de classe enfant. • Tout objet Java qui peut réussir plus d'un test IS-A est considéré comme polymorphe. En Java, tous les objets Java sont polymorphes puisque tout objet passera le test IS-A pour son propre type et pour la classe Object. • Il est important de savoir que le seul moyen possible d'accéder à un objet est via une variable de référence. Une variable de référence ne peut être que d'un seul type. Une fois déclaré, le type d'une variable de référence ne peut pas être modifié. • La variable de référence peut être réaffectée à d'autres objets à condition qu'elle ne soit pas déclarée finale. Le type de la variable de référence déterminerait les méthodes qu'elle peut invoquer sur l'objet. • Une variable de référence peut faire référence à n'importe quel objet de son type déclaré ou à n'importe quel sous-type de son type déclaré. Une variable de référence peut être déclarée comme une classe ou un type F. TOUFIK d'interface. 21 Java Avancé Les Exceptions • Une exception est un problème qui survient lors de l'exécution d'un programme. Lorsqu'une exception se produit, le déroulement normal du programme est interrompu et le programme/l'application se termine anormalement, ce qui n'est pas recommandé. Par conséquent, ces exceptions doivent être gérées. • Une exception peut se produire pour de nombreuses raisons différentes. Voici quelques scénarios dans lesquels une exception se produit. F. TOUFIK • Un utilisateur a entré une donnée invalide. • Un fichier qui doit être ouvert est introuvable. • Une connexion réseau a été perdue au milieu des communications. 22 Java Avancé Les Exceptions • Certaines de ces exceptions sont causées par une erreur de l'utilisateur, d'autres par une erreur du programmeur et d'autres par des ressources physiques qui ont échoué d'une manière ou d'une autre. • Sur cette base, nous avons trois catégories d'exceptions. On doit les comprendre pour savoir comment fonctionne la gestion des exceptions en Java. 1. Les exceptions contrôlées. 2. Les exceptions non contrôlées. 3. Les erreurs. F. TOUFIK 23 Java Avancé Les Exceptions • Les exceptions contrôlées (checked exception) • Une exception contrôlée est une exception qui est vérifiée (notifiée) par le compilateur au moment de la compilation, elles sont également appelées exceptions au moment de la compilation. Ces exceptions ne peuvent pas simplement être ignorées, le programmeur doit gérer ces exceptions. • Par exemple, si on utilise la classe FileReader dans notre programme pour lire les données d'un fichier, si le fichier spécifié dans le constructeur est introuvable, une FileNotFoundException se produit et le compilateur invite le programmeur à gérer l'exception. F. TOUFIK 24 Java Avancé Les Exceptions • Les exceptions non contrôlées (unchecked exception) • Une exception non contrôlée est une exception qui se produit au moment de l'exécution. Celles-ci sont également appelées les exceptions d'exécution (Runtime exception). Ceux-ci incluent des bugs de programmation, tels que des erreurs de logique ou une mauvaise utilisation d'une API. Les exceptions d'exécution sont ignorées au moment de la compilation. • Par exemple, si on déclare un tableau de taille 3 dans notre programme et on veut récupérer le 4-ème élément du tableau, l’exception ArrayIndexOutOfBoundsException se produit. F. TOUFIK 25 Java Avancé Les Exceptions • Les erreurs • Ce ne sont pas du tout des exceptions, mais des problèmes qui surgissent au-delà du contrôle de l'utilisateur ou du programmeur. • Les erreurs sont généralement ignorées dans le code car on ne peut rien faire à propos d'une erreur. • Par exemple, si un débordement de pile (stack overflow) se produit, une erreur se produira. • F. TOUFIK Ils sont également ignorés au moment de la compilation. 26 Java Avancé Les Exceptions • Hiérarchie des exceptions • Toutes les classes d'exception sont des sous-types de la classe java.lang.Exception. La classe Exception est une sous-classe de la classe Throwable. Outre la classe d’Exception, il existe une autre sous-classe appelée Error qui est dérivée de la classe Throwable. • Les erreurs sont des conditions anormales qui se produisent en cas de pannes graves, elles ne sont pas gérées par les programmes Java. Object Throwable Error Exception RuntimeException IOException SQLException F. TOUFIK 27 Java Avancé Les Exceptions • Les méthodes des exceptions • Voici la liste des méthodes importantes disponibles dans la classe Throwable. Méthode F. TOUFIK Description public String getMessage() Renvoie un message détaillé sur l'exception qui s'est produite. Ce message est initialisé dans le constructeur Throwable. public Throwable getCause() Renvoie la cause de l'exception. public String toString() Renvoie le nom de la classe concaténé avec le résultat de getMessage(). public void printStackTrace() Imprime le résultat de toString() avec la trace de la pile sur System.err, le flux de sortie d'erreur. public StackTraceElement [] getStackTrace() Renvoie un tableau contenant chaque élément de la trace de la pile. L'élément à l'index 0 représente le haut de la pile des appels et le dernier élément du tableau représente la méthode en bas de la pile des appels. public Throwable fillInStackTrace() Remplit la trace de pile de cet objet Throwable avec la trace de pile actuelle. 28 Java Avancé Les Exceptions • Interception des exceptions • Une méthode intercepte une exception en utilisant une combinaison des mots-clés try et catch. • Un bloc try/catch est placé autour du code susceptible de générer une exception. • Le code dans un bloc try/catch est appelé code protégé, et la syntaxe pour utiliser try/catch ressemble à ce qui suit: F. TOUFIK 29 Java Avancé Les Exceptions • Interception des exceptions • Le code sujet aux exceptions est placé dans le bloc try. Lorsqu'une exception se produit, cette exception est gérée par le bloc catch associé. Chaque bloc try doit être immédiatement suivi par un bloc catch ou d'un bloc finally. • Une instruction catch implique la déclaration du type d'exception qu’on veut attraper. • Si une exception se produit dans le code protégé, le ou les blocs catch qui suivent le try sont vérifiés. • Si le type d'exception qui s'est produit est répertorié dans un bloc catch, l'exception est transmise au bloc catch comme un argument est transmis à un paramètre d’une méthode. F. TOUFIK 30 Java Avancé Les Exceptions • Interception des exceptions • Exemple: Voici un tableau déclaré avec 3 éléments. Ensuite, le code tente d'accéder au 4ème élément du tableau qui lève une exception. F. TOUFIK 31 Java Avancé Les Exceptions • Multiple blocs de catch • Un bloc try peut être suivi de plusieurs blocs catch. La syntaxe de plusieurs blocs catch ressemble à ce qui suit: F. TOUFIK 32 Java Avancé Les Exceptions • Multiple blocs de catch • Les instructions précédentes illustrent trois blocs catch. • Si une exception se produit dans le code protégé, l'exception est renvoyée au premier bloc catch de la liste. • Si le type de données de l'exception levée correspond à ExceptionType1, elle y est interceptée. Si ce n'est pas le cas, l'exception est transmise à la deuxième instruction catch. Cela continue jusqu'à ce que l'exception soit interceptée ou tombe à travers toutes les catch. F. TOUFIK 33 Java Avancé Les Exceptions • Multiple blocs de catch • Exemple: Voici un segment de code montrant comment utiliser plusieurs instructions try/catch. F. TOUFIK 34 Java Avancé Les Exceptions • Le bloc Finally • Le bloc finally suit un bloc try ou un bloc catch. Un bloc de code finally s'exécute toujours, quelle que soit l'occurrence d'une exception. • L'utilisation d'un bloc finally permet d'exécuter toutes les instructions de type nettoyage, peu importe ce qui se passe dans le code protégé. • F. TOUFIK Le code suivant présente l’utilisation du bloc finally: 35 Java Avancé Les Exceptions • Les exceptions définies par l’utilisateur • On peut créer nos propres exceptions en Java. • pour créer un exception on doit respecter les points suivants: • Toutes les exceptions doivent être un enfant de Throwable. • Pour créer une exception contrôlée (checked exception) , l’exception définie doit étendre la classe Exception. • Pour créer une exception non contrôlée d’exécution (unchecked exception), l’exception définie doit étendre la classe RuntimeException. F. TOUFIK 36 Java Avancé Les Exceptions • Les exceptions définies par l’utilisateur • Pour illustrer l’utilisation de l’exception définie par l’utilisateur, la classe Personne contient une méthode verser() qui lève l’exception SoldeInsuffisantException. F. TOUFIK 37 Java Avancé Fichiers & IO • Le Package IO • Le package java.io contient presque toutes les classes pour effectuer des entrées (input) et des sorties (output) (E/S) (I/O) en Java. • Tous ces flux (Stream) représentent une source d'entrée et une destination de sortie. • Un Stream peut être défini comme une séquence de données. Il existe deux types de Stream: • InPutStream : Le InputStream est utilisé pour lire des données à partir d'une source. • OutPutStream : Le OutputStream est utilisé pour écrire des données vers une destination. Source F. TOUFIK Programme Destination 38 Java Avancé Fichiers & IO • InputStream • Un InputStream est utilisé pour lire les données à partir d'une source dans une application Java. • Les données peuvent être n'importe quoi, un fichier, un tableau, un périphérique ou un socket. • En Java, la classe java.io.InputStream est la classe de base pour tous les flux d'entrée Java IO. InputStream ByteArrayInputStream FileInputStream PipedInputStream ObjectInputStream FilterInputStream DataInputStream F. TOUFIK BufferedInputStream PushBackInputStream 39 Java Avancé Fichiers & IO • Les méthodes InputStream Méthode Description read() utilisée pour lire le prochain octet de données du flux d'entrée. La valeur byte est transmise sur une échelle de 0 à 255. Si aucun octet n'est libre car la fin du flux est arrivée, la valeur -1 est transmise. mark(int arg) utilisée pour marquer la position actuelle du flux d'entrée. Il définit read à limit, c'est-à-dire le nombre maximum d'octets pouvant être lus avant que la position de la marque ne devienne invalide. reset() invoquée par la méthode mark(). Il change la position du flux d'entrée à la position marquée. close() utilisée pour fermer le flux d'entrée et libère les ressources système associées à ce flux. read(byte [] arg) utilisée pour lire le nombre d'octets de arg.length du flux d'entrée au tableau de tampons arg. Les octets lus par la méthode read() sont renvoyés sous la forme d'un int. Si la longueur est zéro, aucun octet n'est lu et 0 est renvoyé à moins qu'il y ait un effort pour lire au moins un octet. skip(long arg) utilisée pour ignorer les octets arg dans le flux d'entrée. markSupported() teste si inputStream prend en charge les méthodes de marquage et de réinitialisation. La méthode markSupported de Java IO InputStream renvoie false par défaut. F. TOUFIK 40 Java Avancé Fichiers & IO • OutputStream • Un OutputStream est utilisé pour écrire les données (un fichier, un tableau, un périphérique ou un socket) vers une destination. • En Java, la classe java.io.OutputStream est la classe de base pour tous les flux de sortie Java IO. OutputStream ByteArrayOutputStream FileOutputStream PipedOutputStream ObjectOutputStream FilterOutputStream DataOutputStream F. TOUFIK BufferedOutputStream PushBackOutputStream 41 Java Avancé Fichiers & IO • Les méthodes OutputStream Méthode Description flush() utilisée pour vider le outputStream Cette méthode force l'écriture des octets de sortie mis en mémoire tampon. close() utilisée pour fermer le outputStream et libérer les ressources système associées au flux. write(int b) utilisée pour écrire l'octet spécifié dans le outputStream. write(byte [] b) utilisée pour écrire des octets de b.length depuis le tableau d'octets spécifié vers outputStream. F. TOUFIK 42 Java Avancé Fichiers & IO • Les types des flux (stream) dans java io OutputStream BufferedReader FileOutputStream FileReader DataOutputStream InputStreamReader BufferedOutputStream OutputStreamReader PrintStream F. TOUFIK ByteStream Stream CharacterStream Reader InputStream PrintWriter FileInputStream Writer DataInputStream BufferedWriter BufferedInputStream FileWriter 43 Java Avancé Fichiers & IO • Byte Stream • Les Byte Stream Java sont utilisés pour effectuer l'entrée et la sortie d'octets de 8 bits (byte). • Les classes les plus fréquemment utilisées sont FileInputStream et FileOutputStream. • Voici un exemple qui utilise ces deux classes pour copier un fichier d'entrée dans un fichier de sortie: F. TOUFIK 44 Java Avancé Fichiers & IO • Character Streams • Les flux de caractères (Character Stream) sont ceux qui sont utilisés pour implémenter l'entrée et la sortie avec 16 bits Unicode. • Plusieurs classes sont associées à des flux de caractères en Java, mais les classes les plus couramment utilisées sont FileReader et FileWriter. • L'exemple ci-dessus, utilise ces deux classes pour copier un fichier d'entrée (ayant des caractères Unicode) dans un fichier de sortie: F. TOUFIK 45 Java Avancé Fichiers & IO • Standard Streams • Tous les langages de programmation prennent en charge les (IO) standard où le programme de l'utilisateur peut prendre une entrée à partir d'un clavier, puis produire une sortie sur l'écran de l'ordinateur. • C ou C++, utilise trois dispositifs standard STDIN, STDOUT et STDERR. De même, Java fournit les trois flux standard suivants: • Entrée standard : Ceci est utilisé pour alimenter les données au programme et généralement le clavier est utilisé comme flux d'entrée standard et représenté par System.in. • Sortie standard : Ceci est utilisé pour afficher les données produites par le programme et généralement l’écran de l'ordinateur est utilisé comme flux de sortie standard et représenté par System.out. • Erreur standard : Ceci est utilisé pour afficher les données d'erreur produites par le programme et généralement l’écran de l‘ordinateur est utilisé comme flux d'erreur standard et représenté par System.err. F. TOUFIK 46 Java Avancé Fichiers & IO • Exemple F. TOUFIK 47 Java Avancé Fichiers & IO • Les dossiers • Un répertoire est un fichier qui peut contenir une liste des fichiers ou des répertoires. • On utilise l’objet File pour créer des répertoires, pour lister les fichiers disponibles dans un répertoire,…. • Il existe deux méthodes utiles de la class File qui peuvent être utilisées pour créer des répertoires: • La méthode mkdir( ) crée un répertoire, true en cas de succès et false en cas d'échec. • Un échec indique que le chemin spécifié dans l'objet File existe déjà ou que le répertoire ne peut pas être créé car le chemin complet n'existe pas encore. F. TOUFIK • La méthode mkdirs() crée à la fois un répertoire et tous les parents du répertoire. • L'exemple suivant crée le répertoire "/user/toufik/desktop/test" 48 Java Avancé Fichiers & IO • Les dossiers • On peut utiliser la méthode list() fournie par l'objet File pour lister tous les fichiers et répertoires disponibles dans un répertoire comme suit: F. TOUFIK 49 Java Avancé JDBC • Qu'est-ce que JDBC (Java Database Connectivity) • JDBC est une API Java permettant à une application Java de se connecter à une base de données, d'envoyer des requêtes SQL et de traiter les résultats. • Objectifs de JDBC • Établir une communication transparente entre une application Java et une base de données relationnelle. • Créer une connexion à la base de données à l'aide des informations de connexion (URL, nom d'utilisateur, mot de passe). • Envoyer des requêtes SQL à la base de données pour effectuer des opérations comme la sélection, l'insertion, la mise à jour et la suppression. • F. TOUFIK Récupérer et manipuler les résultats des requêtes dans l'application Java. 50 Java Avancé • JDBC Architecture JDBC 1. JDBC API • Ensemble d'interfaces et de classes pour interagir avec la base de données (Connection, Statement, ResultSet, …). 2. Driver Manager, Gestionnaire des Pilotes • JDBC API Driver Manager Gère les pilotes JDBC, enregistre et fournit des connexions à la base de données. 3. JDBC Driver, Pilote JDBC • Java App JDBC Driver JDBC Driver MySQL Oracle un ensemble de classes Java qui implémente l'interface JDBC pour une base de données spécifique. • F. TOUFIK Le choix du pilote dépend du type de base de données utilisé. 51 Java Avancé JDBC • Driver Manager • Le DriverManager de JDBC joue un rôle crucial dans la gestion des pilotes JDBC et dans la fourniture de connexions à la base de données. • Depuis JDBC 4.0 (Java 6 et versions ultérieures), l'enregistrement explicite du pilote avec Class.forName n'est plus nécessaire.Le pilote JDBC peut être chargé automatiquement à partir du classpath lorsqu'une connexion est demandée. • F. TOUFIK Exemple de création de connexion (MySQL) 52 Java Avancé • JDBC Exécution de Requêtes SQL • Statement et PreparedStatement sont des interfaces de l'API JDBC permettant d'exécuter des requêtes SQL. Ces interfaces fournissent des méthodes pour envoyer des instructions SQL à la base de données. • Dans cet exemple, un objet Statement est créé à partir de la connexion, et une requête de sélection est exécutée à l'aide de la méthode executeQuery(). Le résultat est stocké dans un objet ResultSet. F. TOUFIK 53 Java Avancé JDBC • Exemple d’insertion avec PreparedStatement • Dans cet exemple, un objet PreparedStatement est utilisé pour exécuter une requête SQL d'insertion avec des paramètres. Les valeurs des paramètres sont définies à l'aide des méthodes setXxx() et la requête est exécutée avec la méthode executeUpdate(). La méthode retourne le nombre de lignes affectées par la requête. F. TOUFIK 54 Java Avancé • JDBC executeQuery Vs executeUpdate • executeUpdate et executeQuery sont deux méthodes de l'interface Statement dans JDBC, et ils sont utilisés pour exécuter des requêtes SQL sur une base de données. Cependant, ils sont utilisés dans des contextes différents en fonction du type de requête que vous souhaitez exécuter. 1. executeQuery : Cette méthode est utilisée pour exécuter des requêtes SQL qui retournent un ensemble de résultats, généralement des lignes de données d'une table. Typiquement, il est utilisé pour les requêtes SELECT. La méthode executeQuery renvoie un objet ResultSet qui contient les résultats de la requête, et vous pouvez itérer sur cet objet pour accéder aux données. 2. executeUpdate : Cette méthode est utilisée pour exécuter des requêtes SQL qui modifient la base de données d'une manière ou d'une autre, comme les requêtes INSERT, UPDATE ou DELETE. Elle renvoie un entier qui représente le nombre de lignes affectées par la requête. La méthode executeUpdate est également utilisée pour exécuter des requêtes DDL (Data Definition Language) telles que la création ou la suppression de tables, où aucune valeur de résultat n'est renvoyée. F. TOUFIK 55 Java Avancé • JDBC Utilisation des Batch dans JDBC • Les batchs permettent d'exécuter un groupement de plusieurs requêtes SQL en une seule opération. • Les batchs dans JDBC offrent une manière efficace d'exécuter plusieurs requêtes en une seule transaction, réduisant ainsi la surcharge des communications avec la base de données. Cependant, il est important de gérer correctement les erreurs et les transactions pour assurer la cohérence des données. F. TOUFIK 56 Java Avancé • JDBC commit() & rollback() • Les méthodes commit et rollback sont des méthodes de l'interface Connection dans JDBC et sont utilisées pour gérer les transactions dans une base de données relationnelle. 1. commit: • La méthode commit valide toutes les modifications apportées à la base de données depuis le dernier appel de commit. • Lorsqu'une transaction est terminée avec succès et que toutes les opérations à l'intérieur de la transaction ont été exécutées avec succès, vous appelez commit pour confirmer ces changements et les rendre permanents dans la base de données. • Après l'appel de commit, les changements sont persistants et visibles pour d'autres transactions. 2. rollback • La méthode rollback annule toutes les modifications apportées à la base de données depuis le dernier appel de commit. • En cas d'erreur ou d'exception pendant l'exécution d'une transaction, vous pouvez appeler rollback pour annuler tous les changements effectués au cours de la transaction et ramener la base de données à son état précédent. • F. TOUFIK Cela permet de garantir la cohérence des données malgré une défaillance ou une condition d'erreur. 57 Java Avancé Generics • Types Génériques en Java • Introduction • Les types génériques ont été introduits dans Java pour fournir une façon plus sûre et plus flexible de manipuler les types. • Ils permettent de créer des classes, interfaces et méthodes qui peuvent fonctionner avec différents types sans sacrifier la sécurité du type. • Avantages des types génériques • Évite les erreurs de type à la compilation. • Réduit le besoin de casting. • Écriture de classes et de méthodes génériques qui peuvent être utilisées avec différents types de données. F. TOUFIK 58 Java Avancé Generics • Syntaxe de base (Classe) • Déclaration de classe générique (1) public class Boite<T> { private T contenu; • Déclaration de classe générique (2) public class Paire<T, U> { private T premier; private U deuxieme; public T getContenu() { return contenu; // Constructeur, getters, setters } } public void setContenu(T contenu) { this.contenu = contenu; } } F. TOUFIK 59 Java Avancé Generics • Syntaxe de base (Méthodes génériques) • Déclaration de méthodes génériques dans une classe non générique : public static <T> T getFirstElement(List<T> liste) { if (liste.isEmpty()) { return null; } return liste.get(0); } • Wildcards (Jokers) : Utilisation de jokers pour des types inconnus public void imprimerListe(List<?> liste) { for (Object element : liste) { System.out.println(element); } } F. TOUFIK 60 Java Avancé • Lambda Introduction aux Fonctions Lambda 1. 2. 3. Définition des fonctions lambda • Les fonctions lambda sont des expressions anonymes pour créer des fonctions de manière concise. • Elles sont également appelées expressions lambda en raison de leur syntaxe compacte. Avantages des fonctions lambda • Réduction de la verbosité du code en comparaison avec les méthodes traditionnelles. • Amélioration de la lisibilité du code, en particulier pour les opérations simples. • Facilitation de la programmation fonctionnelle en Java. Contexte historique (introduction dans Java 8) • Les fonctions lambda ont été introduites dans Java 8 pour faciliter la programmation fonctionnelle. • Elles ont été intégrées pour permettre aux développeurs d'adopter un style de programmation plus concis et moderne. F. TOUFIK 61 Java Avancé • Lambda Syntaxe des Fonctions Lambda 1. 2. 3. 4. F. TOUFIK Format général d'une fonction lambda • (paramètres) -> expression • Les paramètres peuvent être absents, un ou plusieurs, et la flèche -> sépare les paramètres de l'expression. Types de paramètres • Paramètres explicites : (int a, int b) -> a + b • Inférence de type : (a, b) -> a + b Expression lambda et instructions lambda • Expression lambda : x -> x * x • Instructions lambda : { System.out.println("Hello"); } Utilisation des parenthèses • Parenthèses facultatives pour un seul paramètre : x -> x * x • Parenthèses nécessaires pour zéro ou plusieurs paramètres : (x, y) -> x + y 62 Java Avancé Lambda • Interfaces Fonctionnelles 1. Introduction aux interfaces fonctionnelles • Une interface fonctionnelle a une seule méthode abstraite. • Exemple : @FunctionalInterface public interface Calculateur { int calculer(int a, int b); } 2. Interface fonctionnelle prédéfinie : java.util.function • 3. F. TOUFIK Fournit diverses interfaces fonctionnelles utiles : Predicate, Consumer, Function, etc. Exemples d'interfaces fonctionnelles • Predicate : Vérifie une condition. • Consumer : Effectue une opération sans retour. • Function : Transforme un type en un autre. 63 Java Avancé Lambda • Références de Méthodes • Les références de méthodes sont une simplification syntaxique pour les cas où la lambda ne fait qu'appeler une méthode existante. • Les références de méthodes peuvent rendre le code plus lisible dans certains cas. • Il est possible d'utiliser des références de méthodes pour des interfaces fonctionnelles existantes. List<String> noms = Arrays.asList("Ahmed", "Khadija", "Amine"); noms.forEach(System.out::println); F. TOUFIK 64 Java Avancé Lambda • Consumer • Un Consumer représente une opération qui prend un argument et ne retourne aucun résultat. • Il est souvent utilisé pour effectuer des actions sur les éléments d'une collection. List<String> fruits = Arrays.asList("Pomme", "Banane", "Orange"); Consumer<String> afficherFruit = (fruit) -> System.out.println("Fruit : " + fruit); // Premier exemple Avec For for (String fruit : fruits) { afficherFruit.accept(fruit); } // Deuxième exemple Avec forEach fruits.forEach(afficherFruit); F. TOUFIK 65 Java Avancé Lambda • Predicate • Un Predicate représente une condition qui peut être évaluée comme vraie ou fausse. • Il est fréquemment utilisé pour filtrer des éléments dans une collection. List<Integer> nombres = Arrays.asList(1, 2, 3, 4, 5, 6); Predicate<Integer> estPair = (nombre) -> nombre % 2 == 0; // Premier exemple avec For List<Integer> nombresPairs = new ArrayList<>(); for (Integer nombre : nombres) { if (estPair.test(nombre)) { nombresPairs.add(nombre); } } // Deuxième exemple avec stream() List<Integer> nombresPairs = nombres.stream() .filter(estPair) F. TOUFIK .collect(Collectors.toList()); 66 Java Avancé Lambda • Function • Une Function prend un argument et produit un résultat. • Elle est utilisée pour effectuer une transformation sur les éléments d'une collection. List<String> noms = Arrays.asList("Ahmed", "Khadija", "Amine"); Function<String, Integer> longueurDuNom = String::length; // Premier exemple avec for List<Integer> longueursNoms = new ArrayList<>(); for (String nom : noms) { longueursNoms.add(longueurDuNom.apply(nom)); } // Deuxième Exemple avec stream() List<Integer> longueursNoms = noms.stream() .map(longueurDuNom) .collect(Collectors.toList()); F. TOUFIK 67 Java Avancé Lambda • Outre Consumer, Predicate, et Function, Java propose d'autres interfaces fonctionnelles pour des cas spécifiques. • BiConsumer prend deux arguments et effectue une opération sans retour. Map<String, Integer> fruitsEtQuantites = new HashMap<>(); fruitsEtQuantites.put("Pomme", 3); fruitsEtQuantites.put("Banane", 5); fruitsEtQuantites.put("Orange", 2); BiConsumer<String, Integer> afficherFruitEtQuantite = (fruit, quantite) -> System.out.println("Fruit : " + fruit + ", Quantité : " + quantite); fruitsEtQuantites.forEach(afficherFruitEtQuantite); • BiPredicate prend deux arguments et évalue une condition comme vraie ou fausse. BiPredicate<Integer, Integer> estPlusGrandQue = (a, b) -> a > b; boolean resultat = estPlusGrandQue.test(10, 5); • BiFunction prend deux arguments et produit un résultat. BiFunction<String, String, String> concatener = (chaine1, chaine2) -> chaine1 + chaine2; String resultatConcatenation = concatener.apply("Bonjour", "Monde"); F. TOUFIK 68 Java Avancé • Stream Stream 1. Qu'est-ce que Stream ? • Stream est une nouvelle abstraction introduite dans Java 8 pour traiter des séquences de données de manière fonctionnelle. • 2. F. TOUFIK Il permet des opérations de traitement de données de manière déclarative. Caractéristiques de Stream • Stateless : Les opérations sur un Stream n'affectent pas l'état des éléments sous-jacents. • Composable : Les opérations peuvent être combinées pour former des pipelines. • Lazy : Les opérations ne sont effectuées que lorsqu'un résultat est nécessaire. 69 Java Avancé • 1. Stream Utilisation de Stream Création d'un Stream • Les Stream peuvent être créés à partir de différentes sources (collections, tableaux, générateurs, etc.). List<String> noms = Arrays.asList("Ahmed", "Khadija", "Amine"); Stream<String> streamNoms = noms.stream(); 2. Opérations Intermédiaires • Les opérations intermédiaires sont des transformations qui produisent un nouveau Stream. Stream<String> nomsEnMajuscules = streamNoms.map(String::toUpperCase); 3. Opérations Terminales • Les opérations terminales produisent un résultat ou un effet final. long nombreDeMajuscules = nomsEnMajuscules.count(); F. TOUFIK 70 Java Avancé • 1. Stream Opération courantes sur Stream Filtrage avec filter • filter permet de sélectionner les éléments en fonction d'une condition. List<Integer> nombresPairs = nombres.stream() .filter(nombre -> nombre % 2 == 0) .collect(Collectors.toList()); 2. Transformation avec map • map permet de transformer chaque élément du Stream. List<Integer> longueursNoms = noms.stream() .map(String::length) .collect(Collectors.toList()); 3. Réduction avec reduce • reduce combine les éléments pour produire un résultat unique. Optional<String> concatenation = noms.stream() .reduce((nom1, nom2) -> nom1 + ", " + nom2); F. TOUFIK 71 Java Avancé • • DateTime DateTime API • Java DateTime API a été introduite dans Java 8 pour simplifier la manipulation des dates et heures. • Elle remplace les anciennes classes telles que Date et Calendar par un modèle plus moderne et flexible. Principales classes • LocalDate : Représente une date (année, mois, jour) sans information sur le fuseau horaire. LocalDate date = LocalDate.now(); • LocalTime : Représente une heure du jour sans information sur la date et le fuseau horaire. LocalTime time = LocalTime.now(); • LocalDateTime : Représente une combinaison de date et d'heure sans information sur le fuseau horaire. LocalDateTime dateTime = LocalDateTime.now(); • ZonedDateTime: Représente une date et une heure avec des informations sur le fuseau horaire. ZonedDateTime zonedDateTime = ZonedDateTime.now(); F. TOUFIK 72 Java Avancé DateTime • Manipulation des dates et heures • Exemples : • LocalDate : Ajout de jours. LocalDate newDate = date.plusDays(7); • LocalTime : Ajout d’heures. LocalTime newTime = time.plusHours(2); • LocalDateTime : Ajout de mois. LocalDateTime newDateTime = dateTime.plusMonths(3); F. TOUFIK 73 Java Avancé • DateTime Formatage, Parsing & Comparaison de dates • Formatage d’une date: LocalDateTime dateTime = LocalDateTime.now(); String formattedDate = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); • Parsing d'une date à partir d'une chaîne : LocalDateTime parsedDateTime = LocalDateTime.parse("2024-01-27 15:30:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); • Comparaison Comparaison de dates avec isBefore, isAfter, isEqual : boolean isAfter = dateTime1.isAfter(dateTime2); F. TOUFIK 74 Java Avancé JUnit • Les Tests Unitaires • Définition • Un test unitaire est une procédure automatisée destinée à vérifier qu'une partie spécifique d'un programme fonctionne correctement. • Les tests unitaires se concentrent sur des parties isolées du code, généralement des méthodes ou des fonctions, appelées "unités". • F. TOUFIK Objectifs • Validation du Code : S'assurer que chaque composant individuel du logiciel fonctionne comme prévu. • Détection Précoce des Erreurs : Identifier les erreurs le plus tôt possible dans le cycle de développement. 75 Java Avancé • JUnit Junit • • • JUnit est un framework de test unitaire pour Java. Il permet de créer, exécuter et automatiser les tests pour garantir la qualité du code. Annotations principales • • @Test : Annotation pour définir une méthode de test. @Before & @After : Annotations pour définir des méthodes qui s'exécutent avant et après chaque test respectivement. • @BeforeClass & @AfterClass : Annotations pour définir des méthodes qui s'exécutent avant et après l'exécution de la classe de test respectivement. • Assertions • JUnit fournit un ensemble d'assertions pour vérifier les résultats des tests comme : • F. TOUFIK assertTrue, assertFalse, assertEquals, … 76 Java Avancé JUnit public class ExempleTest { // Variable à utiliser dans les tests private static int valeur; @BeforeClass public static void setUpClass() { System.out.println("Mise en place des ressources globales pour la classe"); valeur = 42; } @AfterClass public static void tearDownClass() { System.out.println("Libération des ressources globales pour la classe"); } @After public void tearDown() { System.out.println("Libération des ressources après chaque test"); // Autres nettoyages si nécessaire } @Before public void setUp() { System.out.println("Mise en place des ressources avant chaque test"); // Autres initialisations si nécessaire } @Test public void testAjout() { System.out.println("Test d'ajout"); int resultat = valeur + 10; Assert.assertEquals(52, resultat); } @Test public void testSoustraction() { System.out.println("Test de soustraction"); int resultat = valeur - 5; Assert.assertEquals(37, resultat); } } F. TOUFIK 77