Programmation avec le langage Java

Dimension: px
Commencer à balayer dès la page:

Download "Programmation avec le langage Java"

Transcription

1 Programmation avec le langage Java CENTRE DE CALCUL SYSTÈMES D'INFORMATION NORBERT KAJLER JEAN-MICHEL VIOVY ET L'ÉQUIPE DU CCSI ET DES v 1.3 (septembre 2015)

2 Table des matières Objectifs 11 Pourquoi Java? 13 I - Introduction 15 A. Les langages de programmation...15 B. Origine et historique de Java...18 C. Java aujourd'hui...18 D. Caractéristiques techniques de Java...19 E. Qualités et défauts de Java...20 F. JRE, Java SE, JDK, Eclipse,...21 G. Les différentes «éditions» du langage Java...22 H. Langages et technologies connexes...22 II - Syntaxe de base 25 A. Premiers exemples...25 B. Variables, types, portée, commentaires, Variables et types Types «primitifs» Le type booléen Le type caractère Les types entiers Les types flottants Constantes Déclaration et portée des variables Conventions de nommage Commentaires...31 C. Opérateurs Principaux opérateurs...31 Opérateurs arithmétiques...32 Opérateurs de comparaison...33 Opérateurs booléens...33 Opérateurs bit-à-bit...34 Opérateurs d'affectation...34 Opérateurs d'incrémentation et de décrémentation...35 Autres opérateurs...35 Priorité des opérateurs...35 D. Blocs, instructions de contrôle (tests, boucles, ) Instructions et blocs...36 Instructions de contrôle...37 Exécution conditionnelle...37 Cas multiples...38 Boucles de répétitions...39 Boucles d'itération

3 7. Boucles d'itération «simplifiées» Interruptions des boucles, labels...41 E. Entrées-sorties...42 F. Exemple de programme, compilation, exécution...45 III - Références, tableaux, chaînes de caractères, types énumérés simples 47 A. Références...47 B. Tableaux...48 C. Chaînes de caractères...53 D. Types énumérés simples...55 E. Références constantes...56 IV - Fonctions 57 A. Introduction...57 B. Type de retour et instruction return...58 C. Appel (ou «invocation» ) de fonction...59 D. Fonction et portée...59 E. Programme principal...60 F. Passage des paramètres...60 G. Récursivité...62 H. Surcharge (ou «overloading»)...62 I. Fonctions à nombre variable d'arguments...62 J. Fonctions «natives»...63 V - Algorithmique, complexité, tris 65 A. Algorithme...65 B. Calculabilité...66 C. Heuristique...67 D. Complexité, efficacité...67 E. Algorithmique, classification des algorithmes,...69 F. Problématique du tri...69 G. Tri par sélection...70 H. Tri par insertion...71 I. Tri bulle...72 J. Tri rapide...74 K. Complexité des algorithmes de tri...77 VI - Programmation par objets 79 A. Vocabulaire (classe, instance, objet,...)...79 B. Classes, instances, Classe Attributs

4 Méthodes...81 Constructeur...81 Instanciation (mot-clé : new)...82 Tableau d'objets...83 L'instruction instanceof...83 Destructeur...84 C. This this(...) dans un constructeur this comme référence...84 D. Static Mot-clé static...85 Attribut statique...85 Initialiseur statique...86 Méthode statique...87 Appel de méthode statique...87 Static or not static?...88 E. Visibilité...88 F. Types énumérés...89 VII - Exceptions 91 A. Principe des exceptions...91 B. Gestion des erreurs...91 C. Traitement des exceptions...93 D. Nature des exceptions...93 E. Catégories d'exceptions...94 F. Exceptions contrôlées ou non...94 G. Types d'exception usuels...95 H. Lancement d'exception...95 I. Création de nouveaux types d'exception...96 J. Clause throws...96 K. Assertions...97 VIII - Entrées - Sorties 99 A. Catégories de flux et classes à connaître Les 4 grandes catégories de flux abstraits...99 Principaux flux «concrets» Conversions pour flux binaire Autres conversions de flux B. Fiches pratiques (exemples) En En En En En pratique pratique pratique pratique pratique : : : : : écriture d'un fichier «texte» lecture d'un fichier «texte» sans Scanner lecture d'un fichier «texte» avec Scanner écriture d'un fichier «binaire» lecture d'un fichier «binaire» C. Autres classes à connaître Entrées-sorties en mode «random» Manipulation de fichiers et répertoires

5 IX - Listes, piles, files, arbres 109 A. Problématique commune B. Listes Introduction Fonctions de manipulation Implantation Applications C. Piles Introduction Fonctions de manipulation Piles : implantation Application D. Files Introduction Fonctions de manipulation Implantation Applications E. Arbres Introduction Récursivité Vocabulaire Arbres binaires Numérotation des nœuds Parcours Exemple de parcours RGD en java Fonctions de manipulation d'arbres binaires Implantation Applications X - Paquetages, importation 123 A. Paquetage B. Paquetage et visibilité C. Importation D. Nommage des paquetages E. Organisation en fichiers, compilation et exécution F. Paquetages standards de Java XI - Compléments sur les classes 127 A. Niveaux de visibilité B. Classes ou interfaces internes C. Classes locales et classes anonymes D. Héritage, classe racine, Notion de hiérarchie de classes Héritage Héritage, attributs et méthodes Héritage et visibilité Héritage et références Héritage et constructeurs Redéfinition, spécialisation, masquage Polymorphisme dynamique Méthode abstraite Classe abstraite

6 Classe non dérivable Méthode non redéfinissable Héritage et tableau la classe «Object» Méthode clone() Programmation «générique» via la classe Object E. Introspection XII - Interfaces 139 A. Interfaces B. Exemple d'interfaces C. Autres exemples d'interfaces D. Interfaces prédéfinies en Java E. Héritage entre interfaces F. Implantation d'une interface par une classe G. Interface dans une déclaration d'attribut, variables, H. Interfaces en paramètres de méthodes I. Interfaces «marqueurs» J. Interfaces Serializable, Externalizable et mot-clé transient K. Interfaces fonctionnelles L. Passage d'une fonction/méthode en paramètre de méthode M. Méthodes par défaut N. Corps de méthodes statiques dans une interface O. Comparaison interfaces / classes abstraites XIII - Collections (listes, ensembles, files, tables) 149 A. Introduction B. Deux versions : «paramétrée» ou pas C. Les classes Collections et Arrays D. Fiches pratiques et exemple d'utilisation Utilisation d'une liste Parcours avec un Iterator Exemple d'utilisation de la classe LinkedList Définition d'une relation d'ordre / l'interface Comparable Définition d'ordres multiples / l'interface Comparator E. Principales interfaces et classes L'interface Collection L'interface Iterator Les listes / interface List L'interface ListIterator Les piles / classe Stack Les ensembles / interfaces Set et SortedSet Les files d'attente / interface Queue Implantations de l'interface Queue Les tables d'association / interface Map Table d'association triée / interface SortedMap Principales implantations de l'interface Map Collections et enum

7 XIV - Le paquetage java.lang 159 A. Le paquetage java.lang B. La classe Math C. La classe StrictMath D. La classe System E. La classe Runtime F. La classe Process G. Les classes «enveloppes» H. La classe Character I. La classe Number et ses classes filles J. La classe Enum K. La classe Class L. La classe Field M. La classe Method N. Interfaces pré-définies à connaître XV - Autres classes et interfaces à connaître 167 A. Le paquetage java.util B. Les classes Scanner et Pattern C. La classe Random D. La classe Objects E. Localisation et internationalisation XVI - Documentation automatique (javadoc) 175 XVII - Annotations 177 A. Annotations B. Annotations standards (prédéfinies) en Java C. Définition d'annotations D. Le «checker framework» XVIII - Graphisme et Interface Homme-Machine (IHM) 181 A. Introduction B. Composants prédéfinis d'awt C. Utilisation des conteneurs D. Gestionnaires de présentation E. Événements et programmation événementielle F. Dessiner G. Couleurs H. Polices de caractères I. Images

8 J. Dimensions de l'écran et des composants K. Applet vs application L. Ecrire une applet M. Ecrire une application graphique N. Swing O. Pour aller plus loin XIX - Processus légers (threads) 207 A. Programmation multi-threadée B. Thread C. Classe Thread D. Création de threads E. Suspension / arrêt de thread F. Exemple de thread G. Synchronisation des données H. Synchronisation des exécutions I. Blocages J. Priorités des threads K. Groupement de threads L. Penser à utiliser la documentation XX - Programmation réseau 215 A. Paquetage java.net B. Accès aux protocoles Internet C. Exemple d'utilisation de la classe URL D. Connexion réseau bas niveau E. Exemple de Client F. Exemple de serveur G. Penser à utiliser la documentation XXI - Annexe : ressources complémentaires sur Java 219 XXII - Annexe : ressources complémentaires sur l'algorithmique 223 Index 225 9

9 Objectifs Ce document est conçu pour servir de support de cours principal au tronc commun d'informatique. Il couvre au plus près les aspects algorithmique et programmation de cet enseignement (mais pas les aspects architecture des ordinateurs et systèmes d'exploitation pour lesquels d'autres documents ont été distribués) en suivant autant que possible l'ordre des séances. Il comporte un certain nombre de compléments et d'exemples qui ne seront pas nécessairement détaillés lors des petites classes. Il ne saurait toutefois remplacer un ouvrage de référence sur le langage Java, ou sur l'algorithmique, et encore moins l'ensemble des documentations, cours et bases d'exemples disponibles via le site web de l'ecole. NOTE : ce support de cours a pour origine un diaporama sur la programmation en Java, écrit par Fabien Moutarde et Norbert Kajler. Il s'agit ici d'une version complétement réécrite, avec le concours actif de Norbert Kajler et Jean-Michel Viovy, et la participation de toute l'équipe du CCSI. Cette version utilise la chaîne éditoriale «Scénari». Nous vous remercions par avance de signaler toute erreur ou imprécision aux auteurs. 11

10 Pourquoi Java? Java a été choisi par l'équipe enseignante en tant que compromis entre : langage puissant, incluant un maximum de paradigmes de programmation pertinents à enseigner car généralement non maîtrisés par la plupart des élèves admis en 1 année (typage fort, références, programmation objet, exceptions, événements et programmation réactive, threads,...) ; langage pouvant constituer un 2 langage idéal pour des élèves qui connaissent déjà soit un langage moins riche et/ou moins général que Java (Maple, Mathematica, Pascal, Basic, JavaScript, PHP,...) soit un langage essentiellement fonctionnel (CAML, Lisp,...) de nature très différente ; langage relativement facile à maîtriser sans avoir suivi au préalable un enseignement d'informatique avancé ; langage non-spécialisé, permettant l'écriture de programmes de toutes sortes, de toutes tailles, et dans tous les domaines ; langage largement utilisé dans l'industrie du logiciel 1 ; langage mature et très bien documenté (existence de nombreux cours, FAQs, bases d'exemples couvrant tous les aspects du langage) en anglais français, et bien d'autres langues si besoin ; langage disponible gratuitement sur l'ensemble des matériels, et doté d'une vaste bibliothèque de classes et de nombreux outils de développement également gratuits. Java n'est certes pas optimal sur l'ensemble de ces critères ; il constitue néanmoins du point de vue de l'équipe enseignante le meilleur compromis disponible étant donné l'objectif de cours et les connaissances préalables des élèves. Par ailleurs, l'équipe enseignante considère que la maîtrise d'un langage de programmation donné importe moins que la maîtrise des notions sous-jacentes même si, dans le cas particulier de Java, l'expérience acquise peut être directement valorisée (stages, junior entreprise,...) étant donné le nombre de projets informatiques réalisés à l'aide de ce langage (y compris le développement d'applications Android). Ainsi, apprendre à programmer en Java est avant tout un moyen d'étudier, et pratiquer, un certain nombre de principes et styles de programmation essentiels (et que l'on retrouve dans beaucoup d'autres langages). Ce faisant, l'apprentissage de java constitue une étape dans l'étude de l'informatique en général, et en particulier dans la capacité à écrire des programmes non-triviaux dans un langage fortement typé. A l'issue de cet enseignement, il devrait être assez facile aux élèves qui en auraient besoin d'apprendre à programmer dans n'importe lequel des autres langages très répandus aujourd'hui (C, C++, C#, Python...) ou qui émergent depuis quelques années (Scala, Ruby,...). 1 - Java est en 1 ou 2 place dans les différents classements sur l'utilisation des langages de programmation (TIOBE, Transparent Language Popularity Index, PYPL, RedMonk Programming Language Rankings,...) 13

11 14

12 I- Introduction I Les langages de programmation 15 Origine et historique de Java 18 Java aujourd'hui 18 Caractéristiques techniques de Java 19 Qualités et défauts de Java 20 JRE, Java SE, JDK, Eclipse, Les différentes «éditions» du langage Java 22 Langages et technologies connexes 22 A. Les langages de programmation Niveaux et catégories des langages de programmation : langage binaire assembleur : instructions de base du processeur (transferts entre registres, addition,...) langages «impératifs» : Cobol, Fortran, Basic, Pascal, C, Ada, PHP,... langages de «programmation logique» : Prolog, Mercury,... langages «fonctionnels» : Lisp, Scheme, Clojure, ML/CAML, Haskell, Erlang,... langages «orientés objets» : SmallTalk, Objective C, C++, Java, C#, Scala,... Définition Langage binaire : langage natif de l'ordinateur, spécifique à un type d'ordinateur ; programmes constitués d'une suite de zéros et de uns, directement exécutables par l'ordinateur mais incompréhensibles ou presque par un être humain. Assembleur : langage de «bas niveau» spécifique à un processeur et très proche du langage de l'ordinateur, donc difficile à comprendre pour un être humain mais trivial à transcrire en langage binaire (en assembleur chaque instruction du langage correspond à une instruction élémentaire du processeur, par exemple : affecter une valeur à une case mémoire, comparer deux valeurs, poursuivre l'exécution à une adresse mémoire donnée,...) Langage de «haut niveau» : par opposition au langage binaire et à l'assembleur, langage relativement lisible pour un être humain et nécessitant 15

13 un gros travail de transcription en langage binaire ; les langages de «haut niveau» se déclinent en plusieurs catégories pas forcément exclusives les unes des autres selon le style de programmation qu'ils préconisent : style impératif : le programme correspond à une suite d'instructions totalement explicitées et regroupées en modules/procédures/instructions. style logique : un programme correspond à une suite de «faits» et de «règles» à partir desquels sera créée automatiquement la séquence d'instructions exécutée par l'ordinateur ; dans un langage de «programmation logique» tel que Prolog le code décrit ce qui doit être fait en termes abstraits, sans se préoccuper du comment cela sera fait (ce qui limite en pratique les domaines d'applications et engendre des problèmes de performances) ; en cela les langages de «programmation logique» sont à l'opposé des langages impératifs. style fonctionnel : les programmes sont des fonctions au sens mathématique fonctions «d'ordre supérieur»2 y compris, ce qui fait qu'il n'existe pas de distinction fondamentale entre programmes et données en programmation fonctionnelle (un programme dans un langage fonctionnel tel que Lisp, ML/CAML, Haskell, etc. peut typiquement en cours de traitement produire un autre programme qui crée un troisième programme qui s'applique à des données dont la nature est elle-même un programme). style orienté objets : repose sur un certain nombre d'abstractions positionnées au cœur du langage encapsulation, classes, instances, attributs, méthodes, héritage,... (voir plus loin) ; la plupart des langages orientés objets sont des langages essentiellement impératifs (C++, Java) avec des aspects fonctionnels plus ou moins prononcés. Complément : matérielles Langages de programmation et architectures De nos jours, la quasi totalité des ordinateurs (et smartphones) ont une architecture matérielle (processeur) conçue : 1. pour privilégier la programmation impérative en termes d'efficacité (sans interdire pour autant les autres styles de programmation) ; 2. pour être programmée dans n'importe quel langage (sous réserve qu'il puisse être traduit ou interprété dans le langage binaire du processeur). Il est toutefois possible de créer des ordinateurs privilégiant le style fonctionnel (e.g. les machines Lisp conçues dans les années 70s et commercialisées dans les années 80s mais disparues depuis) ou logique (quelques variantes d'architectures matérielles optimisées pour Prolog dans les années 80-90s). Il est également possible de concevoir des processeurs pour un langage de programmation précis les auteurs de Java ont d'ailleurs un temps travaillé sur un processeur optimisé pour l'exécution de bytecode Java avant d'y renoncer mais, depuis la fin des années 90s, l'envie d'optimiser les performances d'un langage de programmation par la création d'une architecture matérielle spécifique (processeur dédié compris) se heurte à un obstacle majeur d'ordre strictement économique : les coûts de développement des processeurs sont tellement élevés que seules une ou deux architectures polyvalentes par génération se révèlent commercialement viables (présentement : Intel et ARM). Désormais, la puissance atteinte par les processeurs couplée avec les progrès accomplis dans l'optimisation des compilateurs rendent, de fait, peu pertinent le développement de processeurs dédiés à un langage donné. Toutefois, une des 2 - On appelle fonction d'ordre supérieur une fonction prenant d'autres fonctions en paramètres. Par exemple, le calcul formel de la dérivée étant données une fonction et une variable est une fonction d'ordre supérieur. Autre exemple : une fonction qui prend en paramètres deux fonctions f et g et une liste l et qui applique la fonction f à tous les éléments de la liste dont l'image par g est vraie. 16

14 Introduction particularités des processeurs ARM (très utilisés dans les smartphones, tablettes,...) est leur formidable flexibilité, à tel point que certaines versions disposent de mode(s) permettant d'exécuter du bytecode Java plus efficacement3. Principaux langages «généralistes» : Complément Le diagramme ci-dessus présente quelques uns des langages de programmation «généralistes» (permettant d'écrire une grande variété de programmes dans de nombreux domaines) qui ont été développés depuis l'apparition des premiers ordinateurs. Y sont ainsi visibles, les langages généralistes ayant été les plus utilisés au fil des ans et/ou ayant le plus influencé les langages utilisés aujourd'hui. Outre les langages généralistes, il existe des milliers de langages de programmation plus ou moins spécialisés, autrement dit, des langages qui ont été développés pour écrire des programmes dans des domaines spécifiques (e.g. VHDL 4 pour la conception de circuits électroniques), ou pour fonctionner exclusivement à l'intérieur d'un logiciel donné (e.g. ceux utilisés dans Maple ou Mathematica). La frontière entre langages généralistes et spécialisés est toutefois floue et poreuse : historiquement, de nombreux langages ont été initialement développés pour satisfaire un besoin spécifique avant d'être utilisés plus largement. C'est le cas de C (conçu pour créer Unix), de Python, et de Java comme on le verra plus loin. Inversement des langages comme C++, C# ou Scala ont, d'emblée, été conçus pour être des langages généralistes. De même, la frontière entre langages impératifs / fonctionnels / orientés objets n'est 3 - Le mode Jazelle DBX permet, au moins théoriquement, l'exécution directe du bytecode sur les processeurs ARM sans l'intermédiaire d'une machine virtuelle. En pratique, tout dépend de l'implantation du mode Jazelle DBX sachant qu'il existe des dizaines de fournisseurs de processeurs ARM. Au pire le code reste entièrement exécuté dans une machine virtuelle ; au mieux, seule une partie du bytecode est véritablement exécutée directement sur le processeur, les instructions les plus complexes et/ou les moins courantes étant toujours interprétées dans une machine virtuelle. Une variante à Jazelle DBX est par ailleurs incluse dans les processeurs ARM depuis 2005 : ThumbEE, conçu comme le mode d'exécution privilégié pour l'exécution des programmes écrits en Java, C#, Phython, Perl, etc. Dans ce mode, le processeur exécute un jeu d'instructions réduit optimisé pour être très proche de tous ces langages à la fois. L'usage de ThumbEE n'est cependant plus recommandé par ARM sur les dernières générations de ses processeurs, même si il reste disponible pour des raisons de compatibilité avec les anciens processeurs. 4 - VHSIC (Very High Speed Integrated Circuit) Hardware Description Language. 17

15 pas figée : la plupart des langages évoluent au fil des années, et dans certains cas changent de catégorie, en ajoutant une couche objet par exemple (e.g. Pyhthon, PHP et bien d'autres) ou des aspects fonctionnels (Java 8). D'autres langages sont conçus pour être précisément à la frontière de différents styles comme Scala ou F# qui tentent de concilier au mieux les styles impératifs, objets et fonctionnels. Par ailleurs il existe de nombreux «langages informatiques» qui ne sont pas des langages de programmation : par exemple XML (Extensible Markup Language) est un langage conçu pour représenter/archiver/manipuler des données structurées, il ne permet pas l'écriture de «programmes». B. Origine et historique de Java Initialement (1991) «Oak» était un projet de langage pour l'électronique grand public développé au sein de la société Sun (rachetée depuis par Oracle) Principal concepteur : James Gosling Transformé en langage pour le Web sous le nom de «Java» grâce à sa portabilité (1994/95) Lancement officiel en mai 1995 Complément : Historique des versions du langage 1996 : Java : Java 1.1 nombreuses optimisations, modification du modèle des événements pour AWT,... ~400 classes prédéfinies 1998 : Java 1.2 (renommé Java2 ou J2SE 1.2) ajouts : collections, Swing, Java2D,... ~1200 classes prédéfinies 2000 : Java 1.3 (J2SE 1.3) 2002 : Java 1.4 (J2SE 1.4) 2004 : Java 1.5 (J2SE 1.5) ajouts : généricité (proche des templates de C++), types énumérés, web services,... ~2500 classes prédéfinies 2006 : Java 1.6 (ou «Mustang» ou Java SE 6) améliorations des performances (Swing notamment) ajouts : interactions avec scripts (PHP, Python, Ruby, JavaScript), : Java 1.7 (ou «Dolphin» ou Java SE 7) améliorations de la généricité et des instructions switch, catch,... ajouts : NIO (new I/O), try-with,... ~3000 classes prédéfinies 2014 : Java 1.8 (ou «Wolf» ou Java SE 8) améliorations de la gestion du temps et des durées (classes Instant, Duration,...) ajouts : lambda expressions, streams,... ~4000 classes prédéfinies ~2016 : Java 1.9 C. Java aujourd'hui Langage de programmation parmi les plus utilisés aujourd'hui : plus de 10 millions de développeurs Java nombreux outils de développement plusieurs milliards d'objets avec une «machine virtuelle Java», dont : 18

16 Introduction - 5 milliards de cartes à puce (y compris cartes SIM) 3 milliards de téléphones portables 100% des lecteurs de disque «Blu-ray» 90% des PCs d'entreprise D. Caractéristiques techniques de Java Un langage orienté-objet : robuste (typage fort, pas de pointeurs, garbage collector) modulaire (packages) intégrant le multi-threading compilable en bytecode pouvant être interprété (ou exécuté à volée) au sein d'une machine virtuelle Java (JVM) maximise la portabilité Complément : Java et C / C++ Java est proche du langage C++. Historiquement, sa syntaxe de base a été volontairement calquée sur celle de C / C++ afin de faciliter la transition pour les millions de programmeurs qui connaissent déjà ces deux langages. Principales simplifications de Java (par rapport à C++) : pas de manipulations de pointeurs sous forme d'adresse mémoire ; gestion mémoire automatique (garbage collector) ; pas de surcharge des opérateurs ; pas d'héritage multiple 5 ; pas de préprocesseur. Principaux ajouts (par rapport à C++) : tableaux avec test de dépassement de bornes vérifié à l'exécution ; chaînes de caractères sous forme de classe ; notion d'interface ; classe racine ; introspection ; structuration en paquetages ; aspects fonctionnels (depuis Java 1.8) ; multi-threading incorporé au langage ; vaste bibliothèque de classes. Complément : Java et JavaScript Le langage JavaScript n'a rien ou presque à voir avec Java au plan technique : il s'agit d'un langage faiblement typé, beaucoup moins riche que Java en termes de paradigmes de programmation et de bibliothèque de classes. Concernant les usages il y a quelques points communs : l'utilisation à l'intérieur de navigateurs web et de serveurs, mais pour JavaScript c'est quasiment sa seule utilisation alors que pour Java c'est une utilisation parmi bien d'autres. JavaScript est maintenu par la fondation Mozilla ; il fait partie, comme Java, des langages informatiques les plus répandus ; il est en particulier une brique essentielle 5 - Du moins pas au sens de C++ qui permet l'héritage multiple des attributs et des méthodes : en Java seuls les méthodes peuvent dans une certaines mesure faire l'objet d'un héritage multiple via le mécanisme des méthodes «par défaut». 19

17 de la technologie AJAX (asynchronous JavaScript and XML) utilisée pour la création de pages web dynamiques dans lesquelles il y a des échanges fréquents et automatiques entre le navigateur et le serveur (par exemple pour la mise à jour d'une carte). JavaScript et Java sont en fait complémentaires : certains codes très spécifiques s'écrivent plus aisément avec JavaScript (pour la gestion de formulaires dans des pages web par exemple) alors que Java est utilisé beaucoup plus largement pour exécuter des programmes complexes à l'intérieur de pages web ou de serveurs, et pour développer des programmes autonomes de grande taille comme Eclipse. Cette complémentarité est telle qu'il existe plusieurs briques technologiques pour faciliter l'utilisation conjointe des deux langages dont le moteur JavaScript «Nahshorn» (fournit avec Java depuis la version 8) et qui permet l'exécution de code Javascript au sein de la machine virtuelle Java (la JVM) et également l'invocation de code Java depuis Javascript (et réciproquement). E. Qualités et défauts de Java Principales qualités Programmes portables Programmes fiables (rigueur du langage => peu de bogues) Formidable bibliothèque de classes (4000+ classes disponibles en standard) Développement rapide Multiples possibilités de déploiement (applet, web start,...) Langage très répandu grande disponibilité de compétences, documentation, outils,... Capacité prouvée à permettre la réalisation de très gros programmes (e.g. Eclipse = 58 millions de lignes de code!) Principaux défauts Vitesse d'exécution des codes inférieure à C/C++ (dépend des codes) Réputation de sécurité ternie à plusieurs reprises par des bugs dans les implantations de référence Syntaxe relativement verbeuse Système de type non entièrement unifié (types élémentaires / tableaux / classes) Poids du passé encombrement cognitif (beaucoup de classes a «superflues» maintenues pour garantir la compatibilité ascendante des codes Java) Langage difficile pour des programmeurs occasionnels Inversement, langage possiblement trop banal/mature pour des programmeurs expérimentés Complément 20 Une étude de 2012 sur un ensemble de codes de référence met en évidence une vitesse d'exécution des codes Java (J2SE 1.7) inférieure de 44% comparé au langage C++. Il s'agit d'une différence importante dans l'absolu mais, en pratique, rares sont les applications pour lesquelles un tel gain de vitesse justifie à lui seul le choix d'un langage de programmation : les critères essentiels sont bien plutôt la rapidité et le coût de développement des programmes, la fiabilité, la portabilité,... Concernant la verbosité, c'est un point à relativiser : la verbosité de java découle en grande partie d'un choix de conception délibéré lié d'une part au

18 Introduction typage fort et d'autre part à la volonté de faire prendre conscience de certains choix au programmeur. Par ailleurs, l'étendue de la bibliothèque de classes permet, dans certains cas, d'écrire en quelques lignes ce qui prendrait plusieurs pages en C ou C++. Un programmeur averti peut néanmoins préférer un langage moins verbeux. Parmi les points qui peuvent manquer à des programmeurs expérimentés en Java il y a : a. des mécanismes volontairement absents du langages alors qu'il sont présents dans beaucoup de langages de la même génération (pointeurs, héritage multiple, surcharge des opérateurs,...) ; b. des paradigmes disponibles uniquement dans des langages plus récents que Java (évaluation paresseuse, schémas de conceptions intégrés au langage, etc). Il s'agit là aussi de points à relativiser : peu de programmeurs sont véritablement limités par des manques dans le langage Java. En outre, certaines innovations qu'on retrouve dans des langages plus récents tels que Ruby on rail, Scala,... apportent certes puissance et légèreté mais sont parfois difficiles à maîtriser sans un bon niveau technique et un minimum d'expérience dans le développement logiciel. Enfin, Java évolue régulièrement (ajout de la généricité en 2004, ajout des lambda expressions et des Streams en 2014,...) ce qui réduit l'attrait des langages les plus récents. Toutefois, la volonté des concepteurs du langage de garantir une (quasi)-parfaite compatibilité ascendante6 lorsque de nouveaux concepts sont ajoutés tend à alourdir le langage au plan syntaxique. Au fil du temps, ce pourrait d'ailleurs être un avantage décisif pour les langages plus récents que Java : à force d'ajouter des éléments au langage sans remettre en cause la syntaxe d'ensemble, Java devient progressivement moins agréable à utiliser que ses alternatives les plus récentes. F. JRE, Java SE, JDK, Eclipse,... Plusieurs implantations de Java sont disponibles, dont celle d'origine ORACLE/SUN (créateur du langage) et quelques autres Pour exécuter du code Java : le «JRE» (Java Runtime Environment) d'oracle/sun suffit (gratuit et largement disponible) Pour créer du code java, plusieurs possibilités (au choix) : le «Java SE» (Standard Edition) dénommé aussi «JDK» (Java Development Kit) d'oracle/sun (gratuit) contient :compilateur (javac), interpréteur / machine virtuelle (java), divers outils génération doc (javadoc), debugger (jdb),... la plateforme de développement «Eclipse» (gratuite, la plus utilisée) la plateforme de développement «NetBeans» (gratuite, développée par Oracle) ou l'une des nombreuses autres plateformes de développement permettant de dévlopper du code Java En Java, «compatibilité ascendante» veut dire qu'un programme compilé avec une version antérieure du langage continuera à fonctionner de la même manière sur une machine virtuelle plus récente, sans nécessiter de re-compilation ou de modification du code source (à de rares exceptions près). Autrement dit, un code développé pour Java 1.6 pourra fonctionner sur un ordinateur doté d'un environnement d'exécution (JRE) plus récent tel que Java 1.8. L'inverse est faux : un code Java récent ne fonctionnera pas forcément sur un environnement d'exécution plus ancien. Attention : la «compatibilité ascendante» concerne les programmes écrits en langage Java ; si on considère les outils (compilateur et machine virtuelle Java) on doit alors parler de «compatibilité descendante» ou «rétro-compatibilité» (une JVM 1.6 pourra exécuter tout code écrit en Java 1.6 ou avec des versions plus anciennes, mais pas forcément des codes plus récents). 21

19 Complément : OpenJDK, licences,... OpenJDK est une version de Java dont la totalité des composants est strictement dans le domaine public (sources de toutes les classes, de la machine virtuelle, du compilateur,...) OpenJDK est distribué sous licence GNU OpenJDK est une initiative soutenue par une grande partie de l'industrie informatique (Oracle, IBM, Apple, SAP,...) La version standard distribuée gratuitement par Oracle (JRE, Java SE,...) utilise les mêmes codes sources qu'openjdk mais y ajoute des composants qui ne sont pas dans le domaine public ; le résultat est distribué sous une licence spécifique (Binary Code License) G. Les différentes «éditions» du langage Java Plusieurs «éditions» (ou «distributions») du langage co-existent : 1. Java Standard Edition (J2SE ou Java SE) 2. Java Enterprise Edition (J2EE ou Java EE) applications réparties (e.g. services web) 3. Java Micro Edition (J2ME ou Java ME) applications embarquées (e.g. smartphones, TVs,...) 4. Java Card applications embarquées sur cartes à puce (smartcards) Remarque : éditions Différences au sein du langage Java selon les Chaque édition : inclut un ensemble déterminé de packages plus ou moins conséquent ; utilise une «machine virtuelle» possiblement différente. Le langage est donc sensiblement différent selon l'édition utilisée même si les bases restent strictement les mêmes (syntaxe, structures de données, classes de base). H. Langages et technologies connexes Il existe de nombreux langages et technologies connexes dans l'écosystème Java : GWT (Google) pour la création de pages web dynamiques de type googlemaps Xtend (Eclipse.org) variante de Java avec une syntaxe allégée ; se compile en code source Java... Aussi, la machine virtuelle Java est fréquemment utilisée pour exécuter des programmes écrits dans d'autres langages après compilation en bytecode : JavaScript, Scala, Groovy, Clojure, Jython, JRuby,... Remarque : Avantages pour d'autres langages d'utiliser la machine virtuelle Java Au moins trois avantages majeurs pour qui souhaite développer un nouveau langage : 1. pouvoir exécuter le code sur les milliards de machines physiques (PCs, téléphones, cartes de crédits,...) déjà équipés d'une machine virtuelle Java ; 2. aboutir plus rapidement à une première version utilisable du langage : pas 22

20 Introduction besoin de développer sa propre machine virtuelle, ni de multiplier les compilateurs «natifs», il suffit d'écrire un compilateur qui produit du bytecode Java) ; 3. disposer d'un accès aux classes de la bibliothèque Java via leur bytecode. Complément : Java et Android L'essentiel d'android (Google) est écrit en C/C++ (le cœur du système est une variante d'unix/linux) ; Java y est utilisé pour la création des «applications». Le code java compilé en bytecode (fichiers.class) est converti en fichiers.dex (pour Dalvik executable) afin de pouvoir fonctionner sur la machine virtuelle Dalvik qui est une JVM optimisée pour fonctionner sur des téléphones portables, tablettes,... Attention Ce cours correspond à l'édition standard de Java (Java SE) et ne couvre pas les spécificités des autres éditions, ni les langages connexes à Java. 23

21 II - Syntaxe de base II Premiers exemples 25 Variables, types, portée, commentaires, 26 Opérateurs 31 Blocs, instructions de contrôle (tests, boucles, ) 36 Entrées-sorties 42 Exemple de programme, compilation, exécution 45 A. Premiers exemples Remarque : mots-clés Dans l'exemple ci-dessus, int, for, class, public, static et void sont des motclés. Par mot-clé il faut comprendre un mot réservé par les concepteurs du langage, et qu'il est donc impossible d'utiliser dans un programme pour nommer une variable, une fonction,... Java comporte une cinquantaine de tels mots-clés qui seront présentés au fil du cours. 25

22 B. Variables, types, portée, commentaires, 1. Variables et types Définition : Notion de variable nom (identificateur) + type + zone mémoire Deux grandes familles de types en Java : 1. les types «primitifs» (entiers, flottants,...) 2. les types «composites» qui se manipulent références : tableaux énumérations objets interfaces par l'intermédiaire de Remarque Contrairement à certains langages moins fortement typés (Python, Maple,...), Java ne cherche quasiment jamais à «inférer» (deviner) le type des variables : en Java, il faut déclarer le type de chaque nouvelle variable. Cela alourdit l'écriture du code mais permet de gagner en fiabilité (le compilateur interdit les manipulations risquées, le programmeur est obligé d'expliciter ses choix). Par ailleurs, le type d'une variable en Java est fixé une fois pour toute (i.e. il ne peut changer au fur et à mesure des affectations...) 2. Types «primitifs» boolean char (16-bit, Unicode) byte : entier (signé) 8-bit short : entier (signé) 16-bit int : entier (signé) 32-bit long : entier (signé) 64-bit float : flottant (IEEE 754) 32-bit double : flottant (IEEE 754) 64-bit Remarque Le typage est particulièrement strict en Java (comparé à C ou C++ par exemple), ainsi : les conversions automatiques sont peu nombreuses (et seulement vers des types «plus larges», par exemple du type int vers le type long) 26 les conversions manuelles sont restreintes (il est, par exemple, interdit de convertir un booléen en entier)

23 Syntaxe de base 3. Le type booléen Valeurs possibles : true ou false Véritable type Type retourné par les opérateurs de comparaison Type attendu dans tous les tests Ne peut pas être converti en entier Remarque Contrairement à d'autres langages, le type booléen est un type à part entière en Java. En particulier, il n'y a pas de correspondance entre faux et 0 comme c'était le cas historiquement en C/C++ (non-iso). 4. Le type caractère 16-bit valeurs : quasiment tous les caractères de toutes les écritures (mais affichables uniquement si le système possède les polices de caractères adéquates!) Littéraux entre simples quotes : 'a' 'Z'... Caractères spéciaux : '\n' '\t' '\b' '\\' '"'... Possibilité d'utiliser la valeur Unicode : '\u03c0'7 Convertibles automatiquement en int ou long (et manuellement en byte ou short) Inversement, (char)val est le caractère dont le code Unicode est l'entier val Possibilité de tester la nature du caractère : Character.isLetter(c), Character.isDigit(c),... où c est une variable de type char NOTA-BENE : nombreuses fonctions utilitaires dans la classe Character, voir plus loin (cf. La classe Character p 163) et dans la documentation en-ligne de Java Attention Ne pas confondre 'a' et "a" ('a' est un char, i.e. UN SEUL caractère, "a"est une chaîne de caractères de longueur 1) \ suivi directement d'un nombre indique un char donné par son code en octal (base 8) ex. : `\43' est le char de code 4x8+3=35 (et pas le caractère de code 43) Complément : Distance entre caractères L'opérateur - est disponible sur les caractères pour connaître la distance entre deux caractères. Ainsi 'c' - 'a' vaut Cette valeur Unicode correspond à π (la lettre grecque PI en majuscule). 27

24 5. Les types entiers Littéraux de type entier : en base dix : 139 en octal : 0213 en hexadécimal : 0x8b en binaire : 0b Usage possible du caractère _ (augmente la lisibilité) : 17_500_000 L ou l pour spécifier un entier «long» :: 139L Valeurs min/max :: byte = [-128; +127] short = [ ; ] int = [ ; ] long = [ ; ] Conversion automatique seulement vers les types entiers plus grands (int etc...) et vers les types flottants long, Remarque Contrairement à d'autres langages (C, C++,...), il n'existe pas de variantes «nonsignées» de ces types en Java (et donc pas de mot-clé unsigned). Complément : Encodage des entiers en mémoire Le bit de gauche = le signe ; les autres bits = la valeur en binaire en «complément à deux», i.e. ~ x +1, pour les <0. Exemple : 5 en binaire sur 7bits : et donc sous forme de byte (8 bits) avec bit de signe (0) en tête avec bit de signe (1) en tête : (les 7 bits en complément à 2 : = ) 6. Les types flottants Notation «ingénieur» : 2.45e-25 Littéraux de type double par défaut: float x = 2.5; // Erreur double y = 2.5; // OK float z = 2.5f; // OK (f ou F pour spécifier un float) Valeurs min/max (en valeur absolue, hors 0) : float [ e-45 ; e+38 ] double 28 [ e-324 ; e+308 ]

25 Syntaxe de base Valeurs spéciales : Infinity, -Infinity, NaN Conversion automatique : seulement de float double ATTENTION, la conversion «manuelle» en entier tronque la partie décimale : double d = -2.8; int i = (int) d; // ici, i vaut -2 Complément : Encodage des nombres flottants en mémoire La représentation en mémoire suit strictement la norme IEEE-754 Il existe des valeurs «spéciales» représentant +infini, -infini, et 0/0 (NaN=NotANumber) Principe : où est la «mantisse» sous forme d'un nombre dans [0 ; 1] écrit en base 2 () Pour les float, il y a : 1 bit de signe puis 8 bits pour l'exposant puis 23 bits pour la mantisse Pour les double, il y a : 1 bit de signe puis 11 bits pour l'exposant puis 52 bits pour la mantisse 7. Constantes Variable dont la valeur ne peut plus être changée une fois fixée Se déclare avec le mot-clé final : final double PI = ;... ce qui interdit d'écrire ensuite : PI = 3.14; // ERREUR... Possibilité de calculer la valeur de la constante non pas lors de sa déclaration mais plus tard, à l'exécution : final int // OK : //... MAX_VAL = //... MAX_VAL = MAX_VAL; constante «blanche» lirelavaleur(); 1000; // ERREUR... Complément : le mot-clé const En Java, const (à ne pas confondre avec final) est un mot-clé au sens où on ne peut pas l'utiliser librement pour nommer une variable ; cependant il n'est pas utilisé par le langage, au moins dans sa version actuelle. C'est d'ailleurs avec goto le seul mot ainsi «réservé» par le langage sans être effectivement utilisé. 29

26 8. Déclaration et portée des variables Déclaration préalable obligatoire Identificateurs : - caractères Unicode - commencent par une lettre, _ ou $ - ensuite : lettre, chiffre, _ ou $ Exemples : int i; double x, y, z; char c = 'A', d; boolean flag = true; ATTENTION, initialisation obligatoire avant usage : int i, j; j = i; // ERREUR : i non initialisé «Portée» (ou «scope») des variables (= zone de validité de la déclaration) : jusqu'à la fin du bloc englobant (voir plus loin) 9. Conventions de nommage 1. Identificateurs toujours en minuscules, sauf : - majuscule au début des «sous-mots» intérieurs : unnomdevariableoudefonctionordinaire - début des noms en majuscule pour classes et interfaces (et elles seules) : UnNomDeClasse 2. Pour les constantes : tout en majuscules et séparation des mots par _ UNE_CONSTANTE 3. Pour les classes et interfaces : éviter tous les noms déjà utilisés dans le JDK (ex. String, System,...) 4. Pas d'emploi du caractère $ (ni de caractères non ASCII8) Remarque Ces conventions de nommage édictées par les auteurs du langage ne sont pas strictement obligatoires pour faire fonctionner un programme ; elles sont néanmoins fortement recommandées dans la mesure où elles facilitent grandement la lisibilité du code et sa maintenance). Elle sont de fait très largement respectées. 8 - ASCII = American Standard Code for Information Interchange. La norme ASCII date de 1963, c'est l'ancêtre de tous les systèmes d'encodage de caractères en informatique ; les caractères y sont codés sur un octet ce qui limite leur nombre à 256. ASCII a été conçu pour la langue anglaise dont il couvre tous les caractères et symboles usuels. Pour des raisons de compatibilité ascendante, les normes plus récentes qui couvrent davantage de langues sont généralement calquées sur l'ascii pour ce qui concerne les caractères couverts par cette norme (lettres latines sans accents, chiffres, ponctuation courante...). En particulier, sous Unicode, le standard ASCII est intégré sous le label «Basic Latin» (ou C0 Controls and Basic Latin). 30

27 Syntaxe de base 10. Commentaires Plusieurs sortes de commentaires en Java : a/ commentaires techniques sur une ligne : // commentaire -> fin de la ligne int x; // autre commentaire b/ commentaires techniques sur plusieurs lignes : /* commentaire qui s'étend comme ici sur plusieurs lignes */ c/ commentaires destinés à la documentation automatique (javadoc) : /** commentaire pour javadoc */ NOTA-BENE : javadoc = outil qui analyse le code Java, et produit automatiquement une documentation HTML avec la liste des classes, attributs, méthodes... (en y intégrant, le cas échéant, les «commentaires de documentation») Remarque : javadoc Les commentaires «javadoc» se placent juste avant l'entité (classe, attribut, méthode) à laquelle ils se rapportent Voir la section sur javadoc (cf. Documentation automatique (javadoc) p 175) pour plus de détails. C. Opérateurs 1. Principaux opérateurs affectation : arithmétique : + - comparaison : < <= booléen :! opération bit-à-bit (sur les entiers) : opération et affectation simultanées : <<= >>= >>>= pré/post-incrémentation : pré/post-décrémentation : opérateur ternaire : création tableau ou objet (allocation mémoire) : && = * / > ^ % >= & ==!= & += ^ -= ~ << *= /= >> %= >>> &= = ^= ++ --?: new 31

28 2. Opérateurs arithmétiques Opérateur Fonction Usage + addition expr1 + expr2 - soustraction expr1 - expr2 - changement de signe - expr2 * multiplication expr1 * expr2 / division expr1 / expr2 % modulo expr1 % expr2 Attention L'arithmétique entière est «circulaire» : elle produit des résultats mathématiquement faux en cas de dépassement, mais pas d'erreur au sens informatique, sauf lors d'une division par zéro. L'arithmétique décimale (en virgule flottante) produit des erreurs d'arrondis mais n'est pas circulaire : elle produit des valeurs de type infini en cas de dépassement. En cas de division par zéro, l'arithmétique entière produit une erreur informatique (ArithmeticException) tandis que l'arithmétique décimale retourne la valeur spéciale NaN (NotANumber). Les divisions entre entiers produisent le quotient 9 (pas de passage automatique à l'arithmétique décimale). Conséquence : le comportement de l'opérateur / diffère totalement selon la nature des opérandes : / entre deux entiers quotient (donc 5/2 vaut 2 alors que 5.0/2 vaut 2.5) 1/0 «ArithmeticException» (division par zéro prohibée entre entiers) alors que 1.0/0 retourne la valeur Infinity (et 0.0/0 produit la valeur NaN) Les constantes et fonctions mathématiques usuelles sont dans la classe Math (cf. La classe Math p 160) : Math.E Math.PI Math.pow(x,y) Math.sin(x) Math.log(x) 9 - En java, étant donnés deux entiers et, vaut avec qui vaut, ou selon que est <, = ou > à. Exemples : 18/10 vaut 1 ; -18/10 vaut -1 ; -18/-10 vaut 1. 32

29 Syntaxe de base 3. Opérateurs de comparaison Opérateur Fonction == égalité!= inégalité < inférieur strict <= inférieur ou égal > supérieur strict >= supérieur ou égal NOTA-BENE : résultat de type booléen Attention Ne surtout pas confondre == (test d'égalité) et = (affectation) 4. Opérateurs booléens Opérateur Fonction Usage && et (version optimisée) expr1 && expr2 ou (version optimisée) expr1 expr2 ^ ou exclusif (xor) expr1 ^ expr2! négation! expr1 & et (version non optimisée) expr1 & expr2 ou (version non optimisée) expr1 expr2 NOTA-BENE : les opérandes doivent être des expressions à valeur booléenne Remarque Différence entre les versions optimisées et non-optimisées : avec le et optimisé : &&, le deuxième opérande n'est pas évalué si le premier est faux avec le ou optimisé :, le deuxième opérande n'est pas évalué si le premier est vrai 33

30 5. Opérateurs bit-à-bit Opérateur Fonction Usage & et op1 & op2 ou op1 op2 ^ ou exclusif (xor) op1 ^ op2 ~ négation ~ op1 << décalage à gauche (x2) op1 << op2 >> décalage à droite op1 >> op2 >>> décalage à droite non signé (/2) op1 >>> op2 Travaillent sur la représentation binaire NOTA-BENE : opérandes de type entier 6. Opérateurs d'affectation int i, j, k ; final int TMAX = 100 ; // Exemples d'affectations ordinaires : i = 0 ; j = i ; k = TMAX ; // Exemple d'affectations en série : // (évaluation de droite à gauche) i = j = 2 ; // i et j valent 2 // Exemple avec opération combinée : i += 3 ; // équivaut à i = i+3 ; Complément : Différence subtile! L'équivalence entre opérateurs combinés et opération arithmétique suivie d'une affectation n'est pas totale, car (bizarrement) pour les affectation combinées, il y a conversion automatique. Exemple : si i est de type int, i+=3.7; est équivalent à i = (int)(i+3.7); et donc à i+=3;!!! 34

31 Syntaxe de base 7. Opérateurs d'incrémentation et de décrémentation Opérateur Fonction Usage post-incrémentation i++ pré-incrémentation ++i post-décrémentation i-- pré-décrémentation --i Ces opérateurs permettent de compacter le code : n = i++; équivaut à n = i; i = i + 1; n = ++i; équivaut à i = i + 1; n = i; 8. Autres opérateurs Ternaire conditionnel : bool? expr1 : expr2 int v = (x < y)? x : y // v vaut le minimum entre x et y Conversion explicite (ou casting) : (type) double x = 1.7; int i = (int) x; // i vaut 1 double y = -1.7; int j = (int) y; // i vaut Priorité des opérateurs Opérateurs Java (par ordre de priorité décroissante) [ ] - ++expr --expr new / + - +expr -expr expr-~! % << == expr++ (type)expr * < (params) >> > >>> <= >= instanceof!= 35

32 Opérateurs Java (par ordre de priorité décroissante) & ^ &&? : = += -= *= /= &= <<=... -> NOTA-BENE : à priorité égale, évaluation de gauche à droite pour les opérateurs binaires, sauf pour les affectations (=, *=,...) qui s'évaluent de droite à gauche D. Blocs, instructions de contrôle (tests, boucles, ) 1. Instructions et blocs Chaque instruction se termine par un ';' int x = y = z = x, y, z; 10; f(x); (x+y)/2; On peut grouper plusieurs instructions en un bloc (délimité par des accolades) : int a=1, b=2; { // début de bloc int x = a; a = b; b = x; // fin de bloc x = 3; // ERREUR : x est inconnu ici Remarque La portée d'une variable va de sa déclaration jusqu'à la fin du bloc où elle est déclarée 36

33 Syntaxe de base 2. Instructions de contrôle Les instructions de contrôle permettent de modifier l'ordre normal (séquentiel) d'exécution des instructions : 1. exécution conditionnelle : if(...)... else 2. cas multiples : switch(...) case boucles : while(...)... do... while(...) for(...) 3. Exécution conditionnelle Forme minimale (pas de clause else, une seule instruction) : if (boolexpr) instruction; Forme standard : if (boolexpr) { instruction(s); else { instruction(s); // exécutée(s) si VRAI // exécutée(s) si FAUX Possibilité d'imbrication : if (boolexpr) { instruction(s); // exécutée(s) si VRAI else if (boolexpr2) { instruction(s); else { //... Exemple if ( a!=10 ) x = 4; else { //bloc car plusieurs instructions x = 5; y = t+2; Remarque Dans tous les cas : le test est placé entre parenthèses. La partie «sinon» (else) est facultative. Les accolades sont facultatives si il n'y a qu'une seule instruction. Contrairement à d'autres langages, il n'y a pas de mot-clé then en Java. 37

34 4. Cas multiples switch (e) { case cst1: // instruction(s) break; case cst2: // instruction(s) case cst3: // instruction(s) break; default: // instruction(s) break; si e==cst1 si e==cst2 si e==cst3 ou e==cst2 si aucun des cas prévus Avec : e : de type entier ou char ou String ou bien type énuméré (enum) cst1, cst2,... : littéral ou constante (final) Exemple final int ERREUR=-1; int x, y; //... switch(x) { case 0 : y=x; break; case 1 : x=y; break; case ERREUR : System.exit(1); break; default : y=0; Exemple enum Temperature { FROID, TIEDE, CHAUD ; Temperature t; //.. switch(t) { case FROID : //... case TIEDE : //... case CHAUD : //... 38

35 Syntaxe de base Attention Le paramètre de l'instruction switch ne peut pas être de n'importe quel type (les nombres flottants en particulier sont interdits, de même que les instances de classes autres que String). Sauf cas particuliers, une clause break est nécessaire à la fin de chaque branche du switch. A défaut, chacun des codes correspondant aux branches suivantes sera exécuté sans même vérifier la validité des tests associés, ce qui ne correspond que très rarement au fonctionnement souhaité. 5. Boucles de répétitions Deux sortes de boucles «while» en Java : while (boolexpr) { // corps exécuté tant que do { // boolexpr est vrai : // au moins 1 fois : instruction(s); instruction(s); while (boolexpr); // corps exécuté NOTA-BENE : les accolades sont optionnelles si le corps comporte une seule instruction : while (boolexpr) do instruction; instruction; while (boolexpr); Exemples : int y = 10 ; while (y<8) { y *= 2 ; // que vaut y? int z = 10 ; do { z *= 2 ; while (z<8); // que vaut z? while (x>0.0001) x = f(x); 39

36 6. Boucles d'itération for (init ; boolexpr ; incr) { instructions; // corps de la boucle Avec : init : déclarations et/ou affectations, séparées par des virgules (typiquement : initialisation des variables utilisées dans la boucle) incr : expressions séparées par des virgules (typiquement : incrémentation des variables utilisées dans la boucle) Equivaut à : init; while (boolexpr) { instructions; incr; Exemples : int somme=0; for (int i=1 ; i<=n ; i++) { somme += i; for (i=0, j=1 ; i<10 && (i+j)<10 ; i++, j*=2) { //... for ( ; ; ) ; Remarque Possibilité d'avoir plusieurs instructions à la suite dans la zone «initialisation» et/ou «incrémentation» comme dans le 2 exemple ci-dessus (remarquer l'usage de la virgule pour séparer les instructions en question). Inversement, chacun des composants du for peut être vide (voir le 3e exemple : boucle infinie qui ne fait rien!) 7. Boucles d'itération «simplifiées» for (type param : expression) { //... où expression est soit un tableau (de type cohérent avec celui de param), 40 soit un objet implantant l'interface Iterable (cf. Interfaces prédéfinies à connaître p 166)

37 Syntaxe de base Exemple int[] prems = { 2, 3, 5, 7, 11; // prems : tableau d'entiers int somme = 0; for (int i : prems) { somme += i*i; String[] rep = { "oui", "non", "peut-être" ; // rep : tableau de chaînes de caractères for (String s : rep) { System.out.println(s); Attention Contrairement à la version «classique» du for, le 1 paramètre entre parenthèse n'est pas forcément de type entier (son type doit être celui des éléments du tableau). Par ailleurs, les valeurs successives affectées à ce paramètre lors du déroulement de la boucle correspondent aux différentes valeurs présentes dans le tableau (et pas aux indices comme dans la version «classique» du for). DONC ATTENTION : risque d'erreur lorsque le type des éléments est entier si on confond les deux versions de l'instruction «for». 8. Interruptions des boucles, labels Trois instructions permettent d'interrompre le déroulement normal d'une boucle en Java : continue : fait sortir du tour de boucle en cours (passe immédiatement au prochain test de la boucle) break : fait sortir de la boucle return (cf. Type de retour et instruction return p 58) : fait sortir immédiatement de la fonction en cours, et donc, a fortiori, de la boucle en cours Complément : label devant une boucle On peut mettre un «label» devant une boucle Java et utiliser les instructions continue et break (suivies du nom du label) pour indiquer une boucle spécifique. Intérêt : gestion de cas particuliers dans des boucles imbriquées complexes (à éviter dans les autres cas dans la mesure où ces labels rendent le code difficile à relire/vérifier). 41

38 Exemple nomdulabel: while ( f(x) > 0 ) { for ( x : tab) { //... if ( tab[x] > 100 ) { break; // sort de la boucle la plus interne (for) if ( tab[x] < 0 ) { break nomdulabel; // sort de la boucle englobante (while) if ( tab[x] == 0 ) { continue nomdulabel; // saute au prochain test de la boucle // englobante (while) //... Complément : le mot-clé goto En Java, goto est un mot-clé au sens où on ne peut pas l'utiliser librement pour nommer une variable ; cependant il n'est pas utilisé par le langage, au moins dans sa version actuelle. C'est d'ailleurs avec const le seul mot ainsi «réservé» par le langage sans être effectivement utilisé. E. Entrées-sorties Exemple d'écriture sur le flux de sortie standard (écrit sur la console par défaut) : double z = 0.43; System.out.print("z="); System.out.print(z); System.out.println(" et 2z=" + (2*z)); Exemple de lecture sur le flux d'entrée standard (lit depuis le clavier par défaut) : // Lecture d'un caractère à la fois int car = System.in.read(); // Lecture de 10 caractères byte buf[] = new byte[10]; int nblus = System.in.read(buf); Conseil Utiliser la classe Scanner pour lire autre chose que des caractères ou tableaux de caractères (voir ci-après). 42

39 Syntaxe de base Exemple de lecture avec la classe Scanner import java.util.scanner; // Scanner sc = new Scanner(System.in); String ch = sc.next(); // lecture d'un mot int k = sc.nextint(); // lecture d'un entier double val; // teste si un double suit sur le flux d'entrée // (ici il s'agit du clavier) : if ( sc.hasnextdouble() ) { val = sc.nextdouble(); // lecture d'un double String s = sc.nextline(); // lecture d'une ligne ATTENTION : Java utilise, par défaut, le format «local» des nombres (par exemple en français : 2,5 et pas 2.5) ; possibilité de choisir une «localisation» avec la méthode uselocale() (cf. Localisation et internationalisation p 172) Complément : la classe Scanner Il existe une méthode nextxyz() et une méthode hasnextxyz() pour chaque type primitif Xyz exemple pour le type «double» : nextdouble() et hasnextdouble() Lance InputMismatchException si l'élément suivant n'est pas convertible dans le type demandé d'où l'intérêt de tester la présence d'une donnée d'un certain type avant de la lire! Possibilité de choisir un séparateur avec usedelimiter(pattern) Voir plus loin dans le cours pour plus de détails sur les exceptions (cf. Principe des exceptions p 91) et les classes Scanner et Pattern (cf. Les classes Scanner et Pattern p 168) Ecriture formatée avec printf() printf(string, Object...) est une méthode à nombre d'arguments variable qui facilite l'affichage formaté : double rac2 = Math.sqrt(2); System.out.printf("sqrt(2)=%.3f", rac2); // imprime : sqrt(2)=1,414 int i=3; int j=30; int k=303; System.out.printf(" %3d %3d %3d ", i, j, k); // imprime : double x=2.5; double y=-3.755; System.out.printf("x:%+.2f\ny:%+.2f", x, y); // imprime quoi? 43

40 Complément : printf(), format() et la classe Formatter printf() est une méthode d'affichage puissante mais plus complexe d'emploi que print() et println(). Son principal intérêt est de permettre un contrôle fin du formatage des données, en particulier numériques (mais pas seulement)10. Le principe général est de passer en 1 paramètre une chaîne de caractères avec du texte à afficher, et comportant un nombre quelconque de «séquences» introduites par le caractère %. A chaque séquence doit correspondre une variable passée en paramètre à la suite de la chaîne de caractères comme dans les exemples ci-dessus. Les séquences doivent suivre une syntaxe spécifique détaillée dans la documentation en-ligne de la classe Formatter. Pour comprendre les exemples ci-dessus il suffit de savoir que : chaque séquence commence par un caractère % et se termine par une lettre qui spécifie la nature de la variable qui sera substituée à cette séquence, à savoir : s pour une chaîne de caractères ; c pour un caractère ; d pour un entier ; f pour un nombre flottant ; e pour un nombre flottant à afficher en notation «scientifique» ;... le contrôle de l'affichage s'effectue en ajoutant, si besoin, des directives entre le caractère % et la lettre qui termine la séquence, ainsi : %f indique qu'on souhaite afficher à cet endroit un nombre flottant ; %.2f indique qu'on souhaite exactement 2 chiffres après la virgule ; %6.2f indique en outre que l'affichage devra comporter au minimum 6 caractères, y compris la virgule et le signe éventuel (quitte à ajouter des blancs si besoin) ; %+6.2f indique en outre que le signe (+ ou -) devra impérativement s'afficher (par défaut seuls les signes - s'affichent); %6d indique qu'on souhaite afficher à cet endroit un nombre entier occupant 6 caractères au minimum ; %+6d indique en outre que le signe devra impérativement s'afficher. [ NOTA-BENE : beaucoup d'autres directives sont disponibles pour les nombres flottants, et pour chacun des autres types. ] %% permet d'inclure un caractère % sans qu'il soit interprété comme le début d'une séquence Au delà, se souvenir que printf() est une méthode à la fois puissante et flexible ; à privilégier dès qu'un simple print() ou println() ne suffit pas, et ce d'autant plus qu'elle permet de formater des données créées par l'utilisateur dès lors que ces données se conforment à l'interface «Formattable». Outre printf(), il peut être utile de connaître la méthode statique String.format() qui s'appuie sur la même syntaxe que printf() mais se contente de retourner la chaîne de caractères produite au lieu de l'afficher. NOTA-BENE : comme pour tout aspect non-trivial de Java, il ne faut pas chercher à tout découvrir et encore moins tout mémoriser par avance. Concernant, par exemple, printf(), il faut bien comprendre et mémoriser le mode général de fonctionnement, puis, lorsque nécessaire, approfondir ses connaissances en parcourant la documentation de référence en-ligne (l'ensemble des possibilités de 10 - Accessoirement, elle présente l'avantage de fonctionner de manière similaire à la fonction de même nom du langage C, et donc d'être facile d'utilisation pour tous les programmeurs en C. 44

41 Syntaxe de base formatage permises par la classe Formatter occupe 5 pages) et/ou en cherchant des exemples dans une base telle que F. Exemple de programme, compilation, exécution Exemple de programme // Début du fichier : les «import» import java.util.scanner; // Toutes les autres instructions sont dans une // (ou plusieurs) classe(s) public class MonProgramme { // Un programme «ordinaire» contient toujours // une fonction principale (main) : public static void main(string[] args) { System.out.print("Entrez un int : "); Scanner sc = new Scanner(System.in); int n = sc.nextint(); for (int i=0 ; i<n ; i++) { System.out.println(i); // fin de la boucle for // fin de la fonction main // fin de la définition de la classe Compilation et exécution En général, un fichier MaClasse.java doit contenir la classe MaClasse, et elle seule ; pour plus de détails voir organisation en fichiers (cf. Organisation en fichiers, compilation et exécution p 124) La compilation de MaClasse.java MaClasse.class Le fichier MaClasse.class peut être exécuté si et seulement si la classe MaClasse comporte une fonction «main». 45

42 Références, tableaux, chaînes de caractères, types énumérés simples III - III Références 47 Tableaux 48 Chaînes de caractères 53 Types énumérés simples 55 Références constantes 56 A. Références Les références servent à manipuler toutes les variables dont le type n'est pas primitif (i.e. tableaux, objets, types énumérés) A voir comme une sorte de «poignée», un mécanisme intermédiaire entre un nom de variable et l'emplacement en mémoire où est stockée sa valeur NOTA-BENE : plusieurs références différentes peuvent référencer un même objet ou tableau les références sont typées le mot-clé null désigne une référence «vers rien» (compatible avec tous types de référence) une affectation entre références modifie la référence en partie gauche de l'affectation, et non la chose référencée Exemple : int t1[] = {1, 2, int t2[] = t1; t2 = new int[5]; t1 = null; 3; // t2 réf. le même tableau que t1 // t1 reste réf. à {1,2,3 // t1 ne pointe plus vers rien 47

43 B. Tableaux Principes Manipulés par des références Allocation dynamique par new ( taille définissable à l'exécution) Taille fixée une fois pour toute après allocation Taille accessible à tout moment par le «champ» length Indices variant entre 0 et length-1 (et vérification systématique des bornes à l'utilisation) Complément : stockage des tableaux en mémoire Contrairement à C/C++, les tableaux en Java ne sont pas stockés sous forme d'une simple zone mémoire de taille égale à la longueur du tableau multipliée par la taille d'un élément (avec possibilité de naviguer librement dans la zone mémoire ainsi délimitée, et même au delà étant donné le niveau de liberté offert par les opérations sur pointeurs dans ces deux langages). En Java, le stockage d'un tableau inclut sa taille. Surtout, l'accès aux cases du tableau est strictement contrôlé pour interdire toute lecture/écriture en dehors des limites qu'il occupe en mémoire, et plus généralement toute opération non conforme en termes de typage (en Java, chaque élément d'un tableau doit être du type indiqué lors de sa déclaration). Par ailleurs, les tableaux en Java ne sont pas des «instances d'une classe» (voir plus loin) comme dans d'autres langages objet : ce sont des entités particulières, ni type primitif, ni instance de classe. Déclaration, création, initialisation Déclaration : int tab[]; int [] tab2; // 1 forme autorisée // 2 forme autorisée (équivalente) Création : - par new après la déclaration (ou lors de la déclaration) : int tab[]; tab = new int[5]; // déclaration // création - création implicite en cas d'initialisation lors de la création (voir ci-dessous) Initialisation : // A la déclaration : int tab[] = {1, 2, 3; // Lors de la création : tab = new int[] {1, 2, 3; NOTA-BENE : par défaut, les cases du tableau sont initialisées à 0, '\u0000', false ou null (selon le type de base) 48

44 Références, tableaux, chaînes de caractères, types énumérés simples Attention Il ne faut jamais spécifier de dimension (entier entre les crochets) lors : d'une simple déclaration : on doit écrire int tab[]; et surtout pas int tab[5]; d'une création comportant la liste des valeurs initiales : on doit écrire tab = new tab[]{1,2,3,4,5; et surtout pas tab = new tab[5]{1,2,3,4,5; Manipulations usuelles Accès à la taille : int [] tab = new int[5]; int size = tab.length; // size vaut 5 Accès aux valeurs stockées : tab[0] = 1; tab[4] = -1; // RAPPEL : les indices varient entre 0 et length-1 Affichage : for(val : tab) { System.out.println(val) ; // affiche quoi? // ATTENTION : System.out.println(tab) ; // affiche tab en tant que référence // (adresse mémoire où est stockée le contenu) Affectation (attention, l'affectation ne modifie que la référence ) : int t1[] = {1, 2, 3; int t2[] = {4, 5; t1 = t2; // t1 réfèrence le même tableau que t2 // NOTA-BENE : le tableau {1, 2, 3 n'est plus référencé, // l'espace mémoire correspondant sera automatiquement // récupéré par le «ramasse-miette» (GC) afin de // pouvoir le ré-allouer ultérieurement. Recherche, tri, etc. : voir fonctions utilitaires de la classe Arrays (cf. Introduction p 149) Attention Lancement de l'exception (cf. Principe des exceptions p 91) ArrayIndexOutOfBoundsException en cas de tentative d'accès hors des bornes d'un tableau (indice négatif ou >= t.length) Définition On appelle «ramasse-miettes» (en anglais : garbage collector ou encore GC) le mécanisme intégré à l'interpréteur du langage (la machine virtuelle dans le cas de 49

45 Java) qui récupère de manière automatique les zones mémoires allouées puis rendues inaccessibles au fil de l'exécution du programme. Tous les langages n'incluent pas de «ramasse-miette», l'alternative étant de confier au programmeur la tâche de libérer explicitement les zones mémoire dont il n'a plus l'usage (cas des langages C et C++ par exemple). En pratique, la présence d'un «ramasse-miette» simplifie la programmation et rend les programmes plus fiables, mais cela se paye par : une dégradation (et une moindre prévisibilité) des performances à l'exécution ; l'impossibilité de procéder à certaines optimisations très spécifiques liées à l'organisation des données en mémoire. Dans tous les cas, il est essentiel de recycler les zones mémoire sans quoi la taille des programmes grossit inutilement au cours de l'exécution (on parle alors de «fuite de mémoire» ou memory leak en anglais). Exemple public class ExempleTableau { public static void main(string[] args) { // DECLARATION : double[] tab; // CREATION ET DIMENSIONNEMENT : int lg = 1 + (int)( 9*Math.random() ); tab = new double[lg]; // AFFECTATION DES ELEMENTS DU TABLEAU : for (int i=0 ; i<tab.length ; i++) { tab[i] = 1./(i+1); // AFFICHAGE : for (int i=0 ; i<tab.length ; i++) System.out.print(tab[i] + " "); System.out.println(); { Copie de tableaux Méthode «manuelle» : création d'un nouveau tableau, puis copie case par case Copie (sans allocation) par appel de System.arraycopy() : // copie src[0..49] (50 cases) ==> dst[2..51] System.arraycopy(src, 0, dst, 2, 50); Allocation et copie par Arrays.copyOf() ou Arrays.copyOfRange() : // copie int[] t2 // copie int[] t3 50 les 10 premières cases de t dans t2 : = Arrays.copyOf(t, 10); les cases 5,6..79 de t dans t3 : = Arrays.copyOfRange(t, 5, 80);

46 Références, tableaux, chaînes de caractères, types énumérés simples // ATTENTION : copie les cases d'indice [5..80[ Allocation et copie par clonage : int[] copie = t.clone(); ATTENTION : pour un tableau d'objets, les fonctions ci-dessus recopient uniquement les références les mêmes objets sont ensuite partagés par les 2 tableaux NOTA-BENE : déplacement System.arraycopy() : interne dans un tableau possible par // décale le contenu du tableau d'une case vers la droite // (la case t[0] reste inchangée) : System.arraycopy(t, 0, t, 1, t.length-1); Attention : plusieurs points à connaître concernant System.arraycopy(), Arrays.copyOf() et clone() Lorsqu'on utilise System.arraycopy() : le tableau destination doit au préalable avoir été déclaré et dimensionné correctement ; les tableaux source et destination doivent être du même type (sinon, lancement de l'exception ArrayStoreException). Lorsqu'on utilise Arrays.copyOf() ou clone() : le résultat de la fonction est un nouveau tableau créé (l'allocation est faite par Arrays.copyOf()) ; Lorsqu'on utilise Arrays.copyOf() : lorsque la taille demandée est supérieure à la taille du tableau initial les cases finales sont initialisées à la valeur par défaut du type de base, dans le cas contraire les cases en trop sont ignorées. Pour résumer : 1. System.arraycopy() est la méthode la plus puissante/flexible mais aussi la plus délicate à cause du risque de confusion dans les paramètres et de la nécessité d'allouer au préalable le tableau destination. 2. Inversement, clone() et Arrays.copyOf() sont des méthodes plus simples d'emploi à privilégier chaque fois que l'on veut copier dans un nouveau tableau. 3. Dans tous les cas la copie n'est jamais récursive (pas de méthode «deepcopy()» dans Java jusqu'ici). Tableaux d'objets Des tableaux contenant des (références à des) objets d'une classe donnée peuvent être déclarés et créés pour toute classe (prédéfinie ou bien écrite par le programmeur). Par exemple, un tableau de chaînes de caractères modifiables (classe StringBuffer : voir ci-après) se déclare et se dimensionne ainsi : StringBuffer[] tabchaines; tabchaines = new StringBuffer[2]; 51

47 Attention Le dimensionnement d'un tableau d'objets crée uniquement des «cases» pour stocker des références aux objets, mais pas les objets eux-mêmes. Ces références valent initialement null, il faut donc les faire ensuite pointer vers les objets voulus par des affectations, comme dans l'exemple suivant : StringBuffer[] tabchaines; tabchaines = new StringBuffer[2]; // affectation des références du tableau : tabchaines[0] = new StringBuffer("OUI"); tabchaines[1] = new StringBuffer("NON"); Tableaux multi-dimensionnels Il n'existe pas de tableaux à plusieurs dimensions en Java, mais, de manière analogue aux tableaux d'objets, on peut créer des «tableaux de tableaux» : // Déclaration et création : float matrix[][] = new float[2][3]; // matrix référence un tableau de taille 2 // dont chaque case référence un tableau // d'entiers de taille 3 // Utilisation : for (int i=0 ; i<matrix.length ; i++) { for (int j=0 ; j<matrix[i].length ; j++) { matrix[i][j] = i*j; NOTA-BENE : il est possible de créer des formes non rectangulaires : float triangle[][]; int dim; //... triangle = new float[dim][]; for (int i=1 ; i<dim ; i++) { triangle[i] = new float[i]; Quelques (rares) fonctions à connaître sur les tableaux de tableaux : - Arrays.deepEquals(); - Arrays.deepToString(); 52

48 Références, tableaux, chaînes de caractères, types énumérés simples C. Chaînes de caractères Attention Deux classes complémentaires en Java : 1. chaînes immuables (non modifiables) : String 2. chaînes modifiables : StringBuffer La classe String Chaînes immuables Chaînes littérales : "une chaîne" Concaténation par l'opérateur + Exemple : int age = 24; // Création : String s1 = "Age : " + age; // Création par conversion : double x = 1.618; String s2 = String.valueOf(x); // Utilisation : int l = s1.length(); char c = s1.charat(0); int diff = s1.compareto(s2); boolean tst = s2.equals(s1); s2 = s1; s2 = "Bonjour"; String[] sub = s1.split(":"); Attention En java, pour accéder à la longueur, il faut écrire : s.length() si s est de type String et t.length si t est un tableau! Remarque : Les méthodes compareto() et comparetoignorecase() Les méthodes compareto() et comparetoignorecase() prennent en paramètre un objet de type String et le compare à l'instance courante. Plus précisément, s1.compareto(s2) retourne : 0 ssi les deux chaînes sont identiques ; un entier k négatif ssi s1 se situe avant s2 sans l'ordre lexicographique ; un entier k positif sinon. La valeur exacte de k lorsqu'elle est non-nulle est rarement utile en pratique (indication du caractère à partir duquel s1 et s2 se différencient sauf cas particulier où l'une des deux chaînes est sous-chaîne de l'autre ; voir la documentation de la classe String pour plus de détails). Comme son nom le suggère, la méthode comparetoignorecase() ignore les variations de «casse», autrement dit les différences entre majuscules et minuscules. 53

49 Complément Le classe String comporte de nombreuses fonctions utilitaires : test d'égalité partielle : boolean regionmatches(int deb, String s2, int deb2, int fin2) test de début/fin : boolean startswith(string) ; boolean endswith(string),... extraction de sous-chaîne : String substring(int deb, int fin) void getchars(int deb, int fin, char[] dest, int destdeb) découpage : String[] split(string delim) suppression des blancs de début et fin : String trim() changement de casse : String tolowercase() ; String touppercase() ;... substitution de caractères : String replace(char ancien, char nouveau) conversion en chaîne des types de base (méthodes statiques) : String.valueOf(int) ; String.valueOf(double) ; La classe StringBuffer Chaînes modifiables Exemple : // Création en spécifiant la «capacité» initiale : StringBuffer vide = new StringBuffer(1000); // Création à partir d'une String : StringBuffer buf = new StringBuffer("Bonjour"); // Utilisation : int l = buf.length(); char c = buf.charat(0); buf.setcharat(0, 'L'); buf.insert(3, "gues "); buf.append("née"); buf.deletecharat(6); String s = buf.tostring(); String s2 = buf.substring(7, 11); Attention Entre variables de type StringBuffer : pas de compareto() ni de comparetoignorecase() equals() ne teste pas l'égalité des caractères de la chaîne pas d'opérateur + pour concaténer par contre (buf + s) et (s + buf) sont OK si s est une String, mais le résultat est alors de type String 54

50 Références, tableaux, chaînes de caractères, types énumérés simples Complément : capacité et longueur La capacité d'un StringBuffer correspond au nombre maximum de caractères qu'il pourra contenir sans qu'il soit nécessaire de déplacer son contenu en mémoire pour disposer de plus d'espace. La longueur d'un StringBuffer correspond à longueur de la chaîne de caractères stockée dedans (la longueur est toujours inférieure ou égale à la capacité). La capacité initiale peut être choisie via le constructeur comme dans l'exemple cidessus (par défaut, la capacité initiale est de 16 caractères). Lorsque la capacité est insuffisante pour réaliser une opération de type insert() ou append() elle est automatiquement augmentée mais cette augmentation de capacité a un coût en terme de performances à l'exécution. Le programmeur a ainsi le choix entre laisser Java gérer automatiquement la capacité ou la gérer lui-même lorsqu'il connaît par avance la longueur maximum des chaînes qui seront stockées. Les variables de type StringBuffer se caractérisent par le fait que leur capacité et leur longueur peuvent évoluer au fil des opérations effectuées alors que pour les String la longueur est figée une fois la String initialisée (et la capacité est égale à la longueur). Complément : la classe StringBuilder La classe StringBuilder est une variante de la classe StringBuffer (mêmes fonctionnalités). Elle est plus performante que la classe StringBuffer, mais n'est pas utilisable en cas de multi-threading car ses méthodes sont «non-synchronisées» (cf. Synchronisation des exécutions p 210). Conseil Les classes String et StringBuffer comportent bien plus de méthodes que présentées ci-dessus ; penser à consulter la documentation en-ligne pour approfondir le sujet. D. Types énumérés simples Définir un nouveau «type énuméré» permet de typer proprement une variable pouvant prendre un ensemble restreint de valeurs Mot-clef : enum Exemple : enum CouleurFeu { VERT, ORANGE, ROUGE //... CouleurFeu col = CouleurFeu.ROUGE; //... switch(col) { case CouleurFeu.VERT : passer() ; break ; case CouleurFeu.ORANGE : freiner() ; break ; case CouleurFeu.ROUGE : stopper() ; break ; Remarque Pour plus de détails, voir la section consacrée aux types énumérés (cf. Types énumérés p 89). 55

51 E. Références constantes Une référence constante est une référence associée de façon définitive à un tableau ou à un objet donné Mot-clé : final Exemple : final double [] tab = new double[10]; // La référence (tab) est figée : tab = new double[20]; // ici ERREUR // Le contenu du tableau reste modifiable : tab[0] = 1.732; // OK tab[0] = 3.; // OK 56

52 IV - Fonctions IV Introduction 57 Type de retour et instruction return 58 Appel (ou «invocation» ) de fonction 59 Fonction et portée 59 Programme principal 60 Passage des paramètres 60 Récursivité 62 Surcharge (ou «overloading») 62 Fonctions à nombre variable d'arguments 62 Fonctions «natives» 63 A. Introduction Eléments essentiels de structuration en programmation «impérative» En Java, une fonction se caractérise par : - son nom - une liste (possiblement vide) de paramètres typés - un type de retour - un corps (la séquence d'instructions de la fonction) - une visibilité, une liste d'exceptions,... (voir plus loin) 57

53 Premier exemple de fonction Définition : Signature (ou en-tête) et prototype On appelle «signature» ou «en-tête» d'une fonction son nom + la liste de ses paramètres (avec pour chacun son type) On appelle «prototype» d'une fonction son nom + la liste de ses paramètres (avec pour chacun son type) + son type de retour Attention En Java, chaque fonction est obligatoirement définie dans une classe (ex. : la classe prédéfinie Math regroupe des fonctions mathématiques). Contrairement à d'autres langages, les fonctions en Java ne s'imbriquent pas (i.e. toutes les fonctions d'une classe sont définies les unes après les autres). B. Type de retour et instruction return Type de retour : n'importe quel type, ou bien void Instruction de retour : return (suivi de la valeur de retour éventuelle) Exemple : class MaClasse { /* indexde() retourne l index de la valeur v dans t (ou -1 si pas trouvée) */ public static int indexde(float v, float[] t) { int len = t.length; 58

54 Fonctions for (int i=0 ; i<len ; i++) { if (t[i] == v) { return i; return -1; Rappel Attention à bien respecter les conventions de nommage vues précédemment : mafonction() // 1 lettre en minuscule pour les fonctions MaClasse // 1 lettre en majuscule pour les classes C. Appel (ou «invocation» ) de fonction Cas général préfixer par le nom de la classe, exemples : y = Math.sin(x); k = MaClasse.carre(i); A l'intérieur de la même classe, préfixer est inutile, exemple : class MaClasse { public static int carre(int i) { return i*i; public static void main(string[] args) { int x = MaClasse.carre(5); System.out.println(x); // affiche 25 int y = carre(6); System.out.println(y); // affiche 36 D. Fonction et portée Les variables déclarées dans une fonction sont locales à cette fonction Idem pour les paramètres Exemple : class Portee { public static int calcul(int val) { int tmp = 3*val; return tmp; public static void main(string[] args) { int tmp = 1; System.out.println( calcul(9) ); // Que vaut la variable tmp ici? // et val? 59

55 E. Programme principal En Java, l'exécution de programme consiste en la recherche et l'appel d'une fonction (publique) particulière 1. nommée main 2. prenant impérativement un (et un seul) paramètre de type String[] 3. ne retournant rien Exemple, avec utilisation du paramètre : class Echo { public static void main(string [] args) { for (String s : args) { System.out.print(s + " "); // Exemple d'exécution (en mode texte) // L'utilisateur demande l'exécution du programme echo // avec 3 arguments : // java Echo un deux trois // un deux trois Attention : signature imposée de la fonction main Pour qu'un programme Java s'exécute, la fonction main() doit impérativement avoir toutes les caractéristiques listées ci-dessus. En particulier, il doit y avoir un paramètre de type String[], même si on ne s'en sert pas dans le reste du code! F. Passage des paramètres Principe En Java, le passage des paramètres s'effectue toujours «par valeur» (le paramètre formel prend pour valeur une copie de la valeur du paramètre effectif) : Passage par valeur pour les types «primitifs» : public static void echange(int i, int j){ int tmp = i; // i et j : copies locales i = j; j = tmp; public static void main(string[] args){ int a=1, b=2; echange(a, b); // a et b ne sont pas modifiés Passage par valeur (i.e. recopie) des références : public static void ech(string s1, String s2) { String tmp = s1; // s1 et s2 : copies locales s1 = s2; s2 = tmp; public static void main(string[] args) { 60

56 Fonctions String a="oui", b="non"; ech(a, b); // a et b ne sont pas modifiés Quid des objets référencés? public static void increm(int t[]) { for (int i=0 ; i<t.length ; i++) { t[i]++; public static void tronquer(stringbuffer b) { b.deletecharat(b.length() - 1); public static void main(string[] args) { int tab[] = {1, 2, 3; increm(tab); // tab vaut {2, 3, 4 StringBuffer buf = new StringBuffer("oui"); tronquer(buf); // buf vaut "ou" NOTA-BENE : la référence est passée par valeur (la référence passée en paramètre est une copie de l'originale), mais l'objet référencé peut néanmoins être modifié par la fonction (la référence copiée tout comme la référence originale pointent vers le même objet). Remarque En Java (contrairement à ce qui se passe dans d'autres langages) l'ordre d'écriture des fonctions n'a pas d'importance : une fonction peut être invoquée depuis une ligne qui précède sa définition dans le fichier. Toutefois, il est vivement recommandé d'écrire les fonctions dans un ordre qui facilite la compréhension du programme. Exercice class Passage { public static int fonc(int x) { x++; return x; public static void main(string[] args) { int v = 1; int y = fonc(v); // Que valent y et v ici? int[] tab={1, 2, 3; f2(tab); // Etat de tab maintenant? public static void f2(int[] t) { t = new int[] {2, 2; 61

57 G. Récursivité Une fonction peut s'appeler elle-même à condition de bien gérer l'arrêt de la récursion (à défaut : récursion infinie bug à l'exécution) Exercice : cette fonction est incorrecte. Pourquoi? class ExempleRecursif { public static double puiss(double x, int n){ if ( n==1 ) { return x; else { return x*puiss(x, n-1); //... H. Surcharge (ou «overloading») Possibilité de définir (dans la même classe) plusieurs fonctions de même nom, différenciées par le nombre et/ou le type des arguments : class NomClasse { public static int longueur(string s){ return s.length(); public static int longueur(int i){ String si = String.valueOf(i); return si.length(); public static void main(string [] args) { int k = 12345; int lk = longueur(k); // lk vaut 5 String s = "oui"; int ls = longueur(s); // ls vaut 3 Remarque Lors d'un appel de fonction, les arguments doivent être du type prévu ou d'un type convertible automatiquement vers le type prévu. I. Fonctions à nombre variable d'arguments Possibilité de terminer la liste des paramètres d'une fonction par une «ellipse» permettant un appel de fonction avec un nombre variable d'argument(s) de même type (sauf si le type est Object) : public static double[] f(int exp, double... nb) { double[] res = new double[nb.length]; for (int i=0 ; i<res.length ; i++) { res[i] = Math.pow(nb[i], exp); return res; 62

58 Fonctions //... double[] t1=f(2, 2.57); // nb.length vaut 1 dans f double[] t2=f(2, 7.5, 8, 8.5); // nb.length vaut 3 double[] t3=f(2); // nb.length vaut 0 NOTA-BENE : Le paramètre avec «ellipse» est traité dans la fonction comme un tableau Possibilité d'arguments de types hétérogènes via le type Object (cf. la classe «Object» p 134) J. Fonctions «natives» Le mot-clé native dans une déclaration de méthode indique que cette méthode n'est pas codée en Java, mais dans un autre langage, i.e. C ou C++. Le code de la fonction sera recherché dans un fichier à part (une méthode native n'a donc pas de corps). public class NativeExample { //... public native void ff(string s); static { // bloc statique pour charger le code natif correspondant System.loadLibrary ("nativeexample"); //... public static void main (String[] args) { NativeExample n = new NativeExample(); // excute le bloc statique NativeExample.ff("hello"); //... Java inclut par ailleurs : Java Native Interface (JNI) : spécification des règles à respecter dans le nommage et le typage côté C/C++ ; javah : outil permettant de générer un fichier d'en-tête et un squelette de programme C/C++ à partir d'un source Java comportant une ou plusieurs occurrences du mot-clé native. 63

59 Algorithmique, complexité, tris V- V Algorithme 65 Calculabilité 66 Heuristique 67 Complexité, efficacité 67 Algorithmique, classification des algorithmes, 69 Problématique du tri 69 Tri par sélection 70 Tri par insertion 71 Tri bulle 72 Tri rapide 74 Complexité des algorithmes de tri 77 A. Algorithme Définition : Algorithme Spécification d'un schéma de calcul sous forme d'une suite finie d'opérations élémentaires obéissant à un enchaînement déterminé.11 Dans cette définition, le mot «spécification» doit être compris dans un sens assez large : un algorithme peut être spécifié en langage naturel, dans un pseudo-langage, dans un langage informatique, sous forme de diagramme,... l'important étant que la spécification en soit vraiment une en termes d'exhaustivité et de non-ambiguïté. Dans son ouvrage de référence «The Art of Computer Programming (TAOCP)», Donald Knuth privilégie pour sa part un pseudo-langage de bas niveau : l'assembleur MMIX, langage conçu spécifiquement par l'auteur pour garantir que chaque algorithme est à la fois : 1. explicité dans ces moindres détails ; 2. facile à transcrire en code informatique sans perte d'efficacité Cette définition ne fait pas référence à la notion de programme, ni d'ordinateur. C'est bien sûr volontaire. D'autres définitions sont possibles : - «processus systématique de résolution, par le calcul, d'un problème permettant de présenter les étapes vers le résultat à une autre personne physique (un autre humain) ou virtuelle (un calculateur)» (Wikipedia) ; - «Ensemble de règles opératoires dont l'application permet de résoudre un problème énoncé au moyen d'un nombre fini d'opérations. Un algorithme peut être traduit, grâce à un langage de programmation, en un programme exécutable par un ordinateur» (Encyclopédie Larousse). 65

60 Remarque Si la définition ci-dessus est relativement récente (20 siècle), le mot «algorithme» est relativement ancien : il provient de la transcription en latin d'al-khawarizmi, mathématicien perse (9 siècle ap. J.-C.). Le concept d'algorithme remonte à plus loin encore : l'algorithme d'euclide pour le calcul du PGCD fut explicité par son auteur en ~ 300 av. J.-C. ; d'autres algorithmes sont semble-t-il plus anciens encore. NOTA-BENE : un algorithme peut être mis en œuvre de différentes manières : sous forme de programme informatique, de circuit électronique, de machine purement mécanique, de «machine» biologique (cerveau),... Complément : Protection intellectuelle Un algorithme en tant que tel ne peut normalement pas être breveté (en droit européen et américain). Par contre, un programme informatique mettant en œuvre un ou plusieurs algorithmes peut faire l'objet d'un brevet dans certains pays (e.g. USA) mais pas en Europe. Sont brevetables les procédés industriels ou commerciaux basés sur des algorithmes.12 Dans tous les cas, les programmes sont dans tous les pays adhérant aux règles de l'omc protégés en tant qu'œuvres littéraires par le droit d'auteur 13. B. Calculabilité Définition : Calculable (synonyme : décidable) Caractérisation des problèmes (ou fonctions) qui peuvent être résolus par un algorithme14. Cette notion est beaucoup plus récente que celle d'algorithme (années 1930s : théorie de la calculabilité par Hilbert, Gödel, Church, Turing,...) Définition : calculabilité (synonyme : décidabilité) Concept à l'intersection des mathématiques et de l'informatique théorique ; la calculabilité s'intéresse à la distinction fondamentale entre problèmes calculables / non-calculables, aux conséquences de cette distinction,... Remarque Dans la suite de ce cours, on s'intéressera uniquement aux problèmes «calculables» En pratique, délimiter une frontière entre algorithme, logiciel et procédé en vue d'accorder ou refuser un brevet peut être particulièrement délicat, d'où les litiges nombreux en ce domaine. Le problème est aggravé par le nombre relativement faible de personnes maîtrisant à la fois les aspects techniques (informatique théorique) et légaux (droit de la propriété intellectuelle) La protection liée au droit d'auteur est en théorie automatique, elle est liée à l'écriture d'une œuvre originale. Il est toutefois prudent de se placer en situation de pouvoir prouver formellement sa qualité d'auteur, et aussi de pouvoir dater sa création. Cela peut être réalisé en déposant une copie du programme (source et/ou code binaire) chez un huissier, ou un organisme spécialisé tel que l'agence pour la Protection des Programmes (APP) en France Plus formellement (au sens de la théorie de la calculabilité), un problème est décidable si, et seulement si, il peut être décidé (calculé) par l'un ou l'autre des dispositifs suivants : fonctions récursives, machine de Turing, lambda-calcul, machine à compteurs, automate cellulaire, machine de Blum-Shub-Smale, etc. Ces différents dispositifs étant fondamentalement tous équivalents en ceci qu'ils permettent de résoudre exactement la même classe de problèmes : les problèmes décidables. 66

61 Algorithmique, complexité, tris C. Heuristique Définition : Heuristique Méthode de calcul qui, sans être un algorithme, fournit rapidement (en temps polynomial) une solution possiblement non-optimale voire approximative à un problème. En informatique, les heuristiques sont utilisées lorsqu'un problème : 1. est réputé non-calculable ; 2. ou lorsque les algorithmes les plus performants sont trop lents et/ou trop gourmands en mémoire ; 3. ou lorsque la résolution par heuristique se révèle la plus simple à programmer tout en fournissant un résultat satisfaisant. Exemples : les méthodes permettant de faire (bien) jouer un ordinateur au jeu d'échecs ; les méthodes permettant de reconnaître en temps réel des panneaux routiers à partir d'un flux d'images provenant d'une caméra embarquée ; NOTA-BENE : Le mot «heuristique» vient du grec «je trouve»! D. Complexité, efficacité Définition : Complexité Etude des ressources nécessaires à l'exécution d'un algorithme en «temps» et en «espace». NOTA-BENE : dans cette définition, le temps correspond au nombre d'opérations élémentaires exécutées ; et l'espace à la quantité de mémoire nécessaire pour stocker les instructions du programme et les données (y compris les données intermédiaires produites au cours du calcul). Cette définition ne fait pas directement référence à la notion de programme, ni d'ordinateur. C'est volontaire : il s'agit de quantifier de manière théorique les performances intrinsèques d'un algorithme, c-à-d. indépendamment : 1. de son implantation (e.g. sous forme de programme informatique) ; 2. de la machine sur laquelle il va s'exécuter. Pour ce faire, on commencera par caractériser, sous forme d'un entier n, la taille des paramètres d'entrée du problème, ce qui est généralement aisé : pour une liste on choisira le nombre d'éléments, pour un graphe le nombre de nœuds, pour un polynôme on pourra considérer le degré ou le nombre effectif de monômes,... Il conviendra ensuite d'étudier la manière dont chaque grandeur (temps et espace) évolue en fonction de n lorsque n tend vers l'infini (autrement dit le comportement asymptotique des fonctions temps et espace). Ainsi, pour la complexité en temps», on cherchera à déterminer l'ordre de grandeur du nombre d'opérations élémentaires exécutées par l'algorithme lorsque n tend vers l'infini : de manière asymptotique on caractérisera chaque algorithme par une fonction de n telle que : n (linéaire) ou n^2 (quadratique) ou 2^n (exponentiel) ou... Dans les faits, les complexités en temps les plus courantes, sont, par ordre de 67

62 complexité croissante : 1 (temps constant), log n, n (linéaire), n log n, n^2 (quadratique), n^3, 2^n (exponentiel) et n! (factorielle). On utilisera la notation t(n) = O(...) 15 pour exprimer le fait que la complexité en temps correspond à l'ordre de grandeur du nombre d'opérations élémentaires exécutées lorsque n tend vers l'infini. On pourra ainsi écrire que la complexité en temps de tel algorithme est en O(n^2). Idem pour la complexité «en espace». Remarque : Complexité «en moyenne» et «au pire» Pour faire abstraction des jeux de données effectifs, il existe deux approches complémentaires : considérer parmi toutes les possibilités, le jeu de données le plus «défavorable» (i.e. celui menant au temps le plus grand) on parle alors de complexité «au pire» ; considérer la moyenne sur l'ensemble de tous les jeux de données possibles on parle alors de complexité «en moyenne». Les deux notions sont pertinentes lorsqu'on s'intéresse à un algorithme : la complexité en moyenne permet naturellement d'évaluer le comportement ordinaire, celui qui sera a priori observé sur un grand nombre d'exécutions. La complexité «au pire» nous renseigne quant à elle sur ce qui peut arriver de pire en termes de dégradation des performances liée à la nature des données : c'est un élément à prendre en compte lorsqu'il est nécessaire de garantir un certain niveau de performance pour chaque exécution, et pas juste en moyenne. Complément : Lien avec la loi de Moore Rappel : la loi de Moore (dans sa 2 version de 1975) prédit un doublement à prix constant du nombre de transistors sur un micro-processeur tous les 2 ans. Couplé avec l'augmentation des cadences d'horloge et autres améliorations techniques, cette «loi» s'est traduite dans les faits par un doublement de la vitesse des ordinateurs tous les 18 mois depuis son énoncé. Supposons que ce doublement de la vitesse des machines continuera au même rythme durant la décennie à venir. La conséquence sur la vitesse des programmes est évidente si on raisonne à jeu de données identique : tous les programmes pourront s'exécuter ~ 2 fois plus vite tous les 18 mois, soit ~ 100 fois plus vite au bout de 10 ans (à condition de changer d'ordinateur bien sûr!) Mais quelle est son incidence sur la taille des données qu'il est possible de traiter à temps d'exécution constant? Tout dépend de la complexité en temps des algorithmes utilisés. Avec un algorithme de complexité linéaire, acheter un ordinateur neuf permettra de traiter des données ~ 2 fois plus grandes tous les 18 mois, et donc des données ~ 100 fois plus grandes au bout de 10 ans. Naturellement, si l'algorithme est de complexité log(n), le gain sera encore plus important. Inversement si la complexité en temps est quadratique le gain sera de «seulement» ~ 10 fois au bout de 10 ans ; si elle est exponentielle, ou pire, factorielle, le gain sur 10 ans (ou même 100 ans) sera minime dans la taille des données qu'il sera possible de traiter en un temps donné La notation «O majuscule» fait partie des notations Bachmann Landau permettant de caractériser une fonction par une autre, plus simple, dont le comportement asymptotique est identique. Les autres notations pertinentes à cet égard sont : o, Ω, ω et Θ qui différent par la manière dont la seconde fonction s'approche de la première lorsque n tend vers l'infini. 68

63 Algorithmique, complexité, tris Autrement dit, la loi de Moore permet de miser à horizon 10 ans sur : un facteur 100 dans la vitesse des programmes à taille des données identique (quelque soit la complexité des algorithmes utilisés) ; un facteur pouvant varier de 1 à plusieurs milliers dans la taille des données pouvant être traités à temps d'exécution identique (selon la complexité des algorithmes utilisés). Le 2 point est essentiel de par ses conséquences pratiques : si un problème ne peut être résolu sur ordinateur que sur des données de petite taille (car le meilleur algorithme connu est typiquement de complexité exponentielle, ou pire), alors la loi de Moore ne saurait suffire à progresser rapidement dans la possibilité de traiter des données de tailles toujours plus grandes seule la découverte d'un meilleur algorithme permettra le traitement de données de taille significativement plus grande. Définition : Efficacité d'un algorithme Par convention, un algorithme est considéré comme «efficace» si sa complexité en temps est au pire polynomiale16. On pourra qualifier de «très efficaces» les algorithmes en O(n log n), O(n) et, a fortiori, ceux en O(log n). E. Algorithmique, classification des algorithmes, Définition : Algorithmique, algorithmie L'algorithmique (synonyme : algorithmie) est, au sein de l'informatique, la discipline qui s'intéresse aux algorithmes : quel(s) algorithme(s) permet(tent) de résoudre quel problème, avec quelle complexité,... Classification des algorithmes Les algorithmes peuvent être classés selon plusieurs critères : par nature : séquentiel, parallèle ou distribué par famille de problèmes qu'ils résolvent : recherche, tri, parcours, chaînes, numériques, géométriques,... par mode de fonctionnement : itératif, récursif, force brute, glouton,... F. Problématique du tri Avec la recherche dans une liste ou un tableau, trier le contenu d'une liste ou d'un tableau est l'une des opérations les plus courantes dans les applications informatiques. Il peut s'agir de trier des valeurs numériques par ordre croissant ou décroissant, des valeurs littérales par ordre lexicocraphique, ou des valeurs de type quelconque, à condition d'avoir défini une relation d'ordre permettant de répondre à la question : entre deux valeurs x et y quelconque, est ce que x est inférieur à y ou pas (la relation d'ordre n'a pas forcément besoin d'être totale)? 16 - Il s'agit d'une définition à la fois formelle et arbitraire. Elle se révèle en pratique tout à fait pertinente dans la mesure où la quasi-totalité des algorithmes de complexité polynomiale sont dans les faits en O(n^2) ou O(n^3), et pas en O(n^1000)! 69

64 On distingue : les cas où il est possible de recopier et/ou dupliquer l'ensemble des données à trier (si accessibles et pas trop volumineuses) ; ceux où il est nécessaire d'opérer sur place (i.e. par permutations successives de quelques valeurs) tris «en place». Pratiquement, sur des données composites (instances de classe par exemple), le tri se fera suivant un critère défini par le programmeur à partir de tout ou partie des attributs non-statiques de la classe (cf. Attribut statique p 85). Aussi, lorsqu'il s'agit d'objets de grande taille, il est essentiel de procéder par indirection pour éviter de déplacer l'ensemble des données (c'est ce qui se passe automatiquement en Java via le mécanisme des références qui s'impose au programmeur dès qu'il manipule autre chose que des types primitifs). Dans la suite de cette section, on s'intéressera aux différentes manières de trier «en place» un tableau. La complexité en espace sera la même pour tous ces tris (la quantité de mémoire nécessaire quand n tend vers l'infini sera de l'ordre de n par définition de ce qu'est un tri «en place»). La complexité en temps sera étudiée pour chaque algorithme envisagé. G. Tri par sélection Trier le tableau d'entier Pour obtenir 2 Tri par sélection : principe «placer le minimum au début du tableau» Trouver le plus petit élément du tableau et le placer au début Recommencer avec un tableau contenant les N-1 autres nombres 70

65 Algorithmique, complexité, tris Tri par sélection : pseudo-code Faire pour i variant de 0 à N-2 : minimum = i Faire pour j variant de i+1 à N-1 : si t [j] < t [minimum] minimum = j echanger ( t, i, minimum ) Tri par sélection : complexité Faire N-1 fois : Faire i fois ( i=1 puis 2...puis N-2) si t [j] < t [minimum] i comparaisons minimum = j 0 à i affectations échange de t [i] et t[minimum] 1 échange soit : Toujours n(n-1)/2 comparaisons au pire en, en moyenne en Toujours n-1 échanges ~ 3n affectations au pire en, en moyenne en Conclusion Retenir : tri en H. Tri par insertion Trier le tableau d'entier Pour obtenir 2 71

66 Tri par insertion : principe «placer chaque élément à sa place un par un» Placer l'élément t [1] dans le sous-tableau contenant t [0] et t [1]. Placer t [2] dans { t [0], t [1], t [2] Recommencer à placer t [i] dans le sous-tableau de taille i+1 Tri par insertion : pseudo-code Faire pour i variant de 1 à N-1 : ainserer = t[i] Faire pour j de i-1 à 0 : si ainserer < t[j] // on décale t[j+1] = t[j] sinon break // on sort... // Variante j = i-1; Faire tant que j >= 0 et alnserer < t[j] // on décale t[j+1] = t[j] j--; t[j+1] = ainserer // on place l'élément Tri par insertion : complexité Faire N-1 fois : x = t [i+1] 1 affectation i nombres déjà triés : Faire tant que x < t [j] 0 à i comparaisons t [j+1] = t [j] 0 à i affectations Mettre x dans la place laissée vacante. t [j+1] = x 1 affectation Soit : Entre n-1 et n(n-1)/2 comparaisons au pire en,, en moyenne en Entre 2n et n(n-1)/2 affectations au pire en, en moyenne en Conclusion Retenir : tri en I. Tri bulle Trier le tableau d'entier Pour obtenir 2 72

67 Algorithmique, complexité, tris Tri bulle : principe «Faire remonter les éléments légers» A partir de la fin du tableau prendre 2 éléments consécutifs, Les échanger s'ils ne sont pas dans le bon ordre Recommencer... Le 1er élément est alors le plus petit. Recommencer avec un tableau contenant les N-1 autres nombres Tri bulle : pseudo-code Faire pour i variant de 0 à N-2 : Faire pour j variant de N-1 à i+1 si t [j] < t [j-1] echanger (t, j-1, j) Tri bulle : complexité Faire N-2 fois : Faire i fois si t[j] < t[j-1] i comparaisons echanger ( t, j-1, j ) 0 à i échanges Soit : Toujours n(n-1)/2 comparaisons au pire en, en moyenne en Entre 0 et n(n-1)/2 échanges au pire en, en moyenne en Conclusion Retenir : tri en 73

68 J. Tri rapide Trier le tableau d'entier Pour obtenir 2 Tri rapide : principe «diviser pour... aller plus vite» Couper le tableau en deux tableaux dont les K éléments du 1er sont tous plus petits que ceux du second Garder le Kième élément (bien placé) Recommencer avec les 2 tableaux de taille K-1 et N-K Tri rapide : pseudo-code Faire fois : "couper le tableau " : Pour chaque tableau (produit d'un découpage précédent) de taille M entre début et fin : Considérer l'élément t[début] =pivot Faire varier k entre début et fin et déplacer les éléments t[i] pour que : t[i] <= pivot pour i < k et t[i] > pivot pour i > k et t[k] = pivot = t[début] Récursivement, relancer le découpage entre début et k-1, et entre k+1 et fin (si possible) Exécuter trirapide(t, 0, N-1) 74

69 Algorithmique, complexité, tris trirapide(t, debut, fin) Si debut >= fin retourner //c'est fini Sinon k = partitionner (t, debut, fin) trirapide (t, debut, k-1) //partie gauche trirapide (t, k+1, fin) //partie droite Méthode partitionner(t, debut, fin) : Version 1 partitionner(t, debut, fin) pivot = t [debut] et g = debut+1 et d = fin; faire tant que g < d //les indices ne se croisent pas tant que t[d] > pivot d-tant que t[g] <= pivot et g<d g++ si g < d // on n'a pas fini et il faut échanger echanger( t, g, d) // n comparaisons et 0 à n échanges // fin de la boucle, placer le pivot Si pivot > t[d] echanger( t, debut, d ) // 1 échange retourner d Méthode partitionner(t, debut, fin) : Version 2 partitionner(t, debut, fin) pivot = t [debut] et g = debut+1 et d = fin; faire tant que g<=d // les indices ne se croisent pas si t[g] <= pivot g++ sinon si t[d] < pivot echanger( t, g, d) // n comparaisons et 0 à n échanges sinon d-// fin de la boucle, placer le pivot echanger( t, debut, d ) // 1 échange retourner d Méthode partitionner(t, debut, fin) : Version 3 partitionner(t, debut, fin) pivot = t [debut] et placepivot = debut faire i de debut+1 à fin si t [i] < pivot // le pivot doit être décalé placepivot++ echanger( t, placepivot, i ) // n comparaisons et 0 à n échanges // fin de la boucle, placer le pivot sur placepivot echanger( t, debut, placepivot ) // 1 échange retourner placepivot 75

70 Tri rapide : complexité Selon la taille des découpages, le nombre d'étapes varie entre d'opérations peut donc varier entre et De n.log(n) à (n+2)(n+1)/2 comparaisons au pire en, en moyenne en Entre 1 et n échanges au pire en, en moyenne en Conclusion Retenir : tri en 76 et, le nombre

71 Algorithmique, complexité, tris K. Complexité des algorithmes de tri Comparaisons Pire Moy. Affectations Pire Moy. Sélection Insertion Bulle Rapide A retenir au pire en moy. Sélection Insertion Bulle Rapide 77

72 Programmation par objets VI - VI Vocabulaire (classe, instance, objet,...) 79 Classes, instances, This 84 Static 85 Visibilité 88 Types énumérés 89 A. Vocabulaire (classe, instance, objet,...) Définitions : Classe = modèle d'objets ayant les mêmes types de propriétés et de comportements Objet = instance d'une classe (possède ses propres valeurs pour chaque attribut) Instancier une classe = créer une nouvel objet (instance) de cette classe Un premier exemple : la classe Tour 79

73 Un autre exemple : la classe PolygoneRegulier B. Classes, instances, Classe Classe = modèle permettant : 1/ de regrouper des données de types distincts attribut(s) + 2/ de définir des comportements spécifiques méthode(s) + 3/ de spécifier comment créer des instances de la classe constructeur(s) Les attributs (état) contiennent les données propres à l'objet Les méthodes (comportement) sont les opérations applicables à l'objet Invoquer le constructeur crée un nouveau objet La classe peut aussi posséder des attributs et des méthodes partagées par toutes ses instances attributs et méthodes «statiques» (voir plus loin) Exemple // Définition de la classe Cercle : class Cercle { // I : définition des attributs : double rayon=0; // II : définition des constructeurs : // NOTA-BENE : constructeur par défaut si non défini // III : définition des méthodes : double calculersurface() { return Math.PI*rayon*rayon; // Utilisation de cette classe // (ailleurs dans le programme) : Cercle c = new Cercle(); //... c.rayon = 8 ; double surface = c.calculersurface(); 80

74 Programmation par objets NOTA-BENE : la syntaxe pour désigner un attribut ou une méthode d'une classe varie selon qu'on se trouve dans le bloc correspondant à la définition de la classe, ou pas : accès direct aux attributs et méthodes (non-statiques) de l'instance courante depuis l'intérieur de la classe accès via l'opérateur. («point») à l'extérieur de la classe 2. Attributs Attributs = données propres à l'objet (sauf cas particulier des attributs statiques, voir plus loin) Un attribut peut-être de type primitif ou référence Exemple : // Une classe avec trois attributs : class Salarie { String nom ; int age ; double salaire ; // Exemples d'accès aux attributs : // ( on suppose x1 et x2 correctement déclarés // et initialisés, voir ci-après ) System.out.print( x1.nom ); if ( x2.age > 62 ) { NOTA-BENE : un attribut peut-être déclaré constant avec le mot-clé final 3. Méthodes Méthodes = opérations pouvant s'appliquer aux instances de la classe (sauf cas particulier des méthodes statiques, voir plus loin) Exemple de méthodes dans la classe Salarie : void vieillir() { age ++ ; // utilisation : x1.vieillir () ; boolean estmajeur() { return age>=18 ; // utilisation : if(x2.estmajeur ()) {... void modifsalaire(double d) { salaire=d ; // utilisation : x2.modifsalaire(4100.0) ; 4. Constructeur Constructeur : permet de spécifier comment créer des instances de la classe NOTA-BENE : la destruction des instances se fait automatiquement par le «ramasse miettes» (garbage collector ou GC) qui élimine régulièrement tous les objets nonréférencés 81

75 Exemple de constructeur pour la classe Salarie : public Salarie (String n, int a, double s) { nom = n ; age = a; salaire = s; // exemple d'utilisation : Salarie x1 = new Salarie("Léa Duroc", 40, ); Salarie x2 = new Salarie("MisterX", 35, 4000); x2 = x1; // le GC va détruire l'instance correspondant à "MisterX" // qui n'est plus référencée suite à l'affectation ci-dessus. IMPORTANT : jamais de type de retour lors de sa déclaration (sinon Java le considère comme une méthode et pas comme un constructeur) nom = nom de la classe Complément Une classe peut avoir plusieurs constructeurs à condition que leurs signatures soient différentes (il ne peut pas y avoir deux constructeurs pour une même classe avec exactement la même liste de paramètres). Un constructeur fréquemment utile prend pour seul paramètre une instance de la classe afin de s'en servir comme modèle : on appelle un tel constructeur «constructeur par recopie». Dans son corps, on pourra recopier tous les attributs de l'instance passée en paramètre, ou seulement certains en fonctions des spécificités de la classe en question. 5. Instanciation (mot-clé : new) Instancier une classe = créer un nouvel objet de cette classe L'instanciation se fait par l'utilisation du mot-clé new : MaClasse objetdemaclasse = new MaClasse(..) ; L'opérateur new crée un nouvel objet c'est à dire : - appelle un constructeur - alloue la zone mémoire nécessaire - retourne la «référence» correspondant à cette zone mémoire Attention Comme pour les tableaux, on peut séparer 1. déclaration = typage 2. création = allocation mémoire (voir exemple ci-après) NOTA-BENE : les références non encore initialisées par new ont pour valeur null lorsqu'elles sont dans un tableau ou dans une classe (attribut) ; dans les autres cas (variables locales dans une fonction) elles n'ont pas de valeur du tout (erreur de compilation) 82

76 Programmation par objets Exemple Salarie ledg ; la variable ledg a été déclarée et typée (elle pourra stocker des références à des instances de la classe Salarie) //... ledg = new Salarie("Edgar Legrand", 53, 9500); Un espace mémoire référencé par la variable ledg a été alloué et initialisé : il contient l'objet créé, c'est à dire 1. une référence à une String contenant "Edgar Legrand " 2. un entier égal à un double égal à Tableau d'objets ATTENTION : un tableau d'objets est en fait un tableau de références vers objet : Salarie[] tabs = new Salarie[90]; // tabs[0]... tabs[89] valent tous null Il faut donc créer les objets eux-mêmes (après avoir créer le tableau) : tabs[0] = new Salarie("Edgar Legrand", 53, 9500); tabs[1] = new Salarie("Léa Duroc", 40, ); tabs[2] = new Salarie("MisterX", 35, 4000); //... RAPPEL : l'opérateur d'affectation (=) entre références ne copie que la référence, pas l'espace mémoire référencé : Salarie s = new Salarie("Yves Zay", 61, ); tabs[3] = s; tabs[4] = s.clone(); tabs[5] = tabs[3] ; s.age++ ; // modifie s et tabs[3] et tabs[5] mais pas tabs[4] tabs[5].age++ ; // idem : s.age vaut désormais L'instruction instanceof L'opérateur instanceof permet de tester si un objet est, ou n'est pas, instance d'une classe donnée. Ainsi, r instanceof C vaut : - true si r est une référence à un objet pouvant être considéré comme une instance de la classe C - false sinon (y compris si r == null) Remarque instanceof permet aussi tester si un objet est, ou n'est pas, instance d'une classe qui implante une «interface» donnée (cf. Interfaces p 139). 83

77 8. Destructeur Destructeur : permet de définir un comportement lié à la destruction d'une instance Si besoin, ajouter un destructeur à la classe en suivant la syntaxe : protected void finalize() {... Le code sera appelé automatiquement par le «ramasse-miettes» (garbage collector ou GC) juste avant de supprimer chaque objet de la classe Sauf cas très particuliers, le destructeur n'est jamais invoqué explicitement dans un programme Utile en particulier pour «fermer» proprement des fichiers associés à une instance Remarque Le destructeur est appelé une seule fois par instance quoi qu'il arrive (donc pas réappelée par le GC si appelé «à la main» avant) C. This 1. this(...) dans un constructeur Le mot-clé «this» suivi de parenthèses permet d'invoquer un autre constructeur de la classe : Salarie(String n, int a, double s) { nom = n; age = a; salaire = s; Salarie (String n, int a) { this(n, a, 0.0); Salarie (String n) { this(n, 0); 2. this comme référence Le mot-clé «this» en tant que référence désigne l'instance courante : void changerage(int age) { this.age = age; this permet d'accéder à l'attribut «age» qui est masqué dans la méthode changerage() par le paramètre de même nom Remarque this étant par définition une référence sur l'instance courante, on ne peut utiliser this que là où une instance courante existe, c'est à dire : uniquement lors de l'écriture du corps d'une méthode non-statique (cf. Mot-clé static p 85). Il est fréquent d'utiliser la référence «this» comme paramètre pour désigner 84

78 Programmation par objets l'instance courante lors d'un appel de méthode : class Salarie { //... public void dessinerdans ( Fenetre f ) { String fichierimage = "images/ " + age%10 + ".ico"; afficher(f, fichierimage); class Fenetre { //... public void montrerimage (Salarie untel) { untel.dessinerdans(this); cette utilisation de this en tant que référence sur l'instance courante est essentielle : c'est le seul moyen de se passer «soi-même» en paramètre quand on écrit le code d'une méthode. D. Static 1. Mot-clé static Mot-clef static : indique que ce qui suit est lié à la classe en tant que telle plutôt qu'à l'une de ses instances. On peut donner le caractère «statique» à : - un attribut (y compris un attribut constant) ; - un bloc d'instruction (initialisateur) ; - une méthode. 2. Attribut statique Attribut statique : attribut lié à la classe, sa valeur est partagée par toutes les instances de la classe (il n'existe qu'une seule zone en mémoire pour stocker l'unique valeur commune à la classe). Synonyme : attribut de classe Exemple : class Cercle { double rayon; Color couleur; // rayon et couleur : attributs ordinaires // (une valeur par instance) static int nbcercles=0; // attribut «de classe» (une valeur unique pour la classe) // tous les Cercles partageront l'attribut «nbcercles» public Cercle (double r) { rayon = r; nbcercles++; couleur = affectercouleurselonnumero(nbcercles); 85

79 NOTA-BENE : un attribut statique peut-être déclaré constant avec le mot-clé final (on parle alors de «constante de classe»), exemple : class Direction { public static final int NORD=1 ; public static final int EST=2 ; public static final int SUD=3 ; public static final int OUEST=4 ; // Utilisation : // monrobot.tournervers(direction.est) ; 3. Initialiseur statique Initialiseur statique = bloc d'instructions exécuté une seule fois, lors du chargement de la classe dans la machine virtuelle Java (au lancement du programme, donc bien avant toute création d'instance). Intérêt : permet d'initialiser une variable statique à l'aide de plusieurs instructions, exemple : class Cercle { double rayon; static int nbcercles=0; static int [] tcomp; // attribut de classe non initialisé! static Color couleur; // idem static { // initialiseur statique tcomp = new int [3] ; for (int comp : tcomp) { comp = *Math.random() ; // initialise couleur à une valeur aléatoire unique et // ni trop claire ni trop sombre ( 100<=comp<200 ) couleur = new Color(tComp[0], tcomp[1], tcomp[2]); 86 //.

80 Programmation par objets 4. Méthode statique Méthode statique : méthode s'appliquant à la classe en tant que telle, et pas à une instance en particulier Synonyme : méthode de classe Equivalent des fonctions «ordinaires» des langages non-objet Exemples : Math.log(double) // déclarée static dans Math static void main(string[] args) { // fonction principale // (à déclarer impérativement comme static) class Cercle { static private int epaisseur=1; static public void modifierepaisseurdutrait(int e) { epaisseur = e; 5. Appel de méthode statique Appel depuis une autre méthode de la même classe : class Cercle { //... public void bidule () { modifierepaisseurdutrait(2) ; Appel depuis l'extérieur de la classe : Cercle.modifierEpaisseurDuTrait(2); // il faut préfixer avec le nom de la classe Remarque Le même principe s'applique pour l'accès aux attributs statiques. 87

81 6. Static or not static? E. Visibilité Recommandations pour l'usage des mots clés : public, private,... Obligatoire : - la classe contenant la fonction main doit être publique - un fichier.java ne peut contenir qu'une classe publique (au maximum) Conseillé : - les attributs sont généralement privés si besoin, créer des «accesseurs» (méthodes publiques qui renvoient ou modifient la valeur d'un attribut privé) - sauf cas très particuliers : les constructeurs sont publics - les méthodes auxiliaires purement internes à une classe sont évidemment privées - les méthodes dialoguant avec d'autres classes seront publiques Voir plus loin pour détails sur public / private / protected /... (cf. Niveaux de visibilité p 127) Exemple class Contact { // Attributs -> private (ou protected) : private String nom; private String mail; private long tel ; // Constructeur(s) -> public : public Contact (String n, String m, long t) { nom = n ; mail = m ; tel = t; normaliser(); // Méthode(s) : selon leur nature // accesseur -> public : 88

82 Programmation par objets public String renvoienom() { return nom; // service rendu par la classe -> public : public void envoyermail(string s) {... // Méthode(s) auxiliaire(s), à usage interne // -> private (ou protected) : private void normaliser() {... F. Types énumérés Mot-clef enum au lieu de class Equivaut à une classe ayant un nombre FINI d'instances, toutes prédéfinies Syntaxe spécifique, peut servir dans un switch voir types énumérés «simples» (cf. Types énumérés simples p 55) Exemple d'énumération «simple» : enum Reponse {OUI, NON, PEUT_ETRE //... Reponse r1 = Reponse.OUI ; Intérêt double : lisibilité du code + fiabilité (impossible d'affecter une valeur non prévue) Types énumérés «élaborés» Un enum étant une classe, il peut avoir des attributs et des méthodes Exemple : enum Jeune { BEBE ("Bebe", 0, 3), ENFANT ("Enfant", 3, 12), ADO ("Adolescent", 12, 18) ; private String type ; private int agemin ; private int agemax ; Jeune (String t, int amin, int amax) { type = t ; agemin = amin ; agemax = amax ; public String renvoietype () { return type ; public String renvoieagemin () { return agemin ; public String renvoieagemax () { return agemax ; 89

83 VII - Exceptions VII Principe des exceptions 91 Gestion des erreurs 91 Traitement des exceptions 93 Nature des exceptions 93 Catégories d'exceptions 94 Exceptions contrôlées ou non 94 Types d'exception usuels 95 Lancement d'exception 95 Création de nouveaux types d'exception 96 Clause throws 96 Assertions 97 A. Principe des exceptions Mécanisme pour traiter les anomalies se produisant à l'exécution (division entière par zéro, référence nulle, fichier inacessible,...) Principe fondamental séparer détection et traitement des anomalies : signaler tout problème dès sa détection mais regrouper le traitement des problèmes ailleurs, en fonction de leur type B. Gestion des erreurs Exemple Que fait-cette fonction? static void divtab(int [] tab) { Scanner sc = new Scanner(System.in); int index = sc.nextint(); int div = tab[index]; for (int j=0 ; j<tab.length ; j++) { tab[j] /= div; 91

84 Exemple Gestion des erreurs sans utiliser d'exceptions : static void divtab2(int [] tab) { if( tab == null ) { System.err.println("tab==null") else { Scanner sc = new Scanner(System.in); int index = sc.nextint(); if( index<0 index>=tab.length ) { System.err.println("index incorrect"); else { int div = tab[index]; if( div == 0 ) { System.err.println("diviseur nul"); else { for (int j=0 ; j<tab.length ; j++) { tab[j] /= div; Exemple Gestion des erreurs en utilisant des exceptions : static void divtab3(int[] tab) { try { Scanner sc = new Scanner(System.in); int index = sc.nextint(); int div = tab[index]; for (int j = 0 ; j < tab.length ; j++) { tab[j] /= div; catch (NullPointerException e) { System.err.println("tab==null"); catch (ArrayIndexOutOfBoundsException e) { System.err.println("index incorrect"); catch (ArithmeticException e) { System.err.println("diviseur nul"); finally { // on passe toujours ici NOTA-BENE : toute exception générée provoque l'arrêt brutal du programme ; pour éviter cela, prévoir la capture et le traitement des exceptions ; mots-clefs : try, catch et finally Conseil 1. Eviter de créer un bloc try{... catch... séparé autour de chaque instruction pouvant poser problème (car cela conduirait à un code pas 92

85 Exceptions tellement plus clair qu'avec des if/else imbriqués) faire plutôt un bloc try{... catch... le plus gros possible. 2. Ordonner les clauses catch du plus spécifique (en premier) au plus général (vers la fin), avec si besoin une clause finally à la fin. C. Traitement des exceptions 1. Si une exception est générée dans le bloc try {... : i. l'exécution s'arrête là (on n'exécute pas les instructions du bloc try qui suivent l'instruction à l'origine de l'erreur) ii. on saute dans le premier gestionnaire catch compatible avec cette exception (i.e. attrapant exactement le type d'exception généré, ou exception «ancêtre» au sens de l'héritage) iii. on exécute les instructions du bloc catch iv. puis on continue APRÈS l'ensemble try {... catch (...) { Si pas de catch adéquat, on remonte au try «englobant» le plus proche, on y cherche un catch correspondant, etc... avec possibilité de remonter ainsi jusqu'à la fonction main 3. Si pas non plus de catch adéquat au niveau de la la fonction main arrêt complet du programme 4. Le bloc finally est facultatif : il est exécuté à la fin du bloc try quoiqu'il arrive (fin normale, sortie par return, sortie après catch, ou avec exception non traitée) D. Nature des exceptions Définition Une exception est une instance de la classe Exception ou d'une de ses sous-classes Divers types d'exceptions (classes) sont prédéfinies en Java, et susceptibles d'être générées automatiquement à l'exécution, par exemple : division par zéro (entre entiers) ArithmeticException indice de tableaux hors limites tentative «d'utilisation» d'une référence nulle fichier inaccessible tentative de lire au delà d'une fin de fichier ArrayIndexOutOfBoundsException NullPointerException FileNotFoundException EOFException NOTA-BENE : on peut aussi définir de nouveaux types d'exceptions (cf. Création de nouveaux types d'exception p 96) Rappel Lorsqu'une variable c1 de type C (une classe quelconque) contient une référence nulle, les écritures suivantes sont interdites (elles génèrent le lancement d'une NullPointerException) : int x = c1.a ; // tentative d'accès à l'attribut a de la classe C ; c1.m() ; // tentative d'accès à la méthode m de la classe C ; De même lorsqu'une variable t de type tableau contient une référence nulle, il est interdit d'écrire : 93

86 int l = t.length ; // tentative d'accès à la taille du tableau ; Arrays.sort(t) ; // cette méthode interdit les paramètre (cf. doc. de la classe prédéfinie Arrays) références nulles en Pour mémoire, une variable dont le type n'est pas un type primitif contient une référence nulle tant que l'instance (ou le tableau) n'a pas été «créée» par new. Elle peut aussi contenir une référence nulle si on lui affecte explicitement la valeur null (par exemple pour provoquer la destruction de l'instance précédemment référencée par cette variable). E. Catégories d'exceptions Classe mère : Throwable Erreurs «système» : classe Error (dérivée de Throwable) Autres anomalies : classe Exception (dérivée de Throwable) et ses sous-classes Cas particuliers : classe RuntimeException (dérivée de Exception) et ses sousclasses exceptions «non contrôlées» (voir plus loin) Fonctionnement identique pour les erreurs et les exceptions : NomException(String) : constructeur avec message explicatif sur la cause de l'exception String getmessage() : renvoie le message explicatif en question String tostring() : renvoie le type de l'exception (nom de sa classe) et le message explicatif void printstacktrace() : affiche la pile d'appel jusqu'au point de lancement de l'exception Complément : la classe Error (et les classes qui en dérivent) La classe Error est réservée aux erreurs décelées par la machine virtuelle lors de son fonctionnement «normal» consistant à interpréter du bytecode. Exemple : la sous-classe OutOfMemoryError est lancée par la machine virtuelle quand l'ordinateur manque de mémoire pour continuer l'exécution d'un programme. Dans un code Java ordinaire on ne doit jamais instancier la classe Error et ses sousclasses (on doit instancier et lancer uniquement des exceptions). F. Exceptions contrôlées ou non Les exceptions de type RuntimeException et ses sous-classes (par exemple ArithmeticException, NullPointerException,...) sont dites «non contrôlées» (ou «unchecked») Java n'impose pas leur prise en compte (par défaut : arrêt du programme avec message d'erreur standard) Toutes les autres exceptions sont dites «contrôlées» (ou «checked») Java impose qu'elles soient prises en compte lors de l'écriture du programme, les instructions susceptibles d'en lancer doivent donc se situer : soit dans un bloc try{ avec un catch() correspondant au type d'exception en question ; soit dans une méthode dotée de la clause throws (cf. Clause throws p 96) adéquate. 94

87 Exceptions G. Types d'exception usuels Remarque Le diagramme ci-dessus présente quelques une des erreurs et exceptions les plus courantes prédéfinies en Java. Dans le diagramme chaque rectangle correspond à une classe et les flèches pointent vers la classe «mère» au sens de l'héritage (cf. Héritage p 129). H. Lancement d'exception Possibilité de lancer «manuellement des exceptions» (en plus de celles générées automatiquement) Mot-clef : throw Exemple : if (test_anomalie) { throw new Exception("blabla"); if (autre_test) { throw new IllegalArgumentException("bla"); Effet : interrompt immédiatement le cours normal du programme pour rechercher un gestionnaire adéquat englobant (cf. Traitement des exceptions p 93) 95

88 Conseil Lancer de préférence une exception d'un type spécifique à l'anomalie (et contenant un texte précisant la nature de l'anomalie). I. Création de nouveaux types d'exception Java permet de définir de nouveaux types d'exception : il suffit de créer une sousclasse de Exception ou de RuntimeException (ou d'une de leurs sous-classes prédéfinies) : class MonException extends Exception { MonException(String s) { super(s); // // //... puis plus loin : if (test_anomalie) { throw new MonException("commentaire"); J. Clause throws Chaque méthode doit utiliser une clause «throws» pour déclarer toutes les exceptions «contrôlées» : 1. qu'elle envoie elle-même (par throw) 2. qu'elle «laisse passer» (i.e. émises par des méthodes appelées, et non traitées localement par un try/catch) Exemple : //... void lire() throws MonException, IOException { // lancement explicite d'une exception si pb. : if (testanomalie() == true) { throw new MonException("bla"); // appel d'une méthode susceptible de générer // une exception contrôlée de type IOException : int car = System.in.read(); Conséquence devoir de capture : si une méthode m1 appelle une méthode m2 susceptible de lancer une exception contrôlée (donc avec une clause throws dans la définition de m2), alors m1 doit impérativement : - soit invoquer m2 dans un bloc try/catch permettant de capturer cette exception - soit déclarer elle aussi cette exception dans une clause throws Rappel Toutes les exceptions sont «contrôlées» sauf celle dérivant de RuntimeException. 96

89 Exceptions K. Assertions Le mot-clé assert donne accès à un mécanisme de nature assez proche des exceptions : les assertions. Il s'agit de positionner dans un code java des lignes telles que : assert r!= null ; assert t >= 0 : "t doit être positif ou nul!" qui vont interrompre l'exécution du programme lorsque la condition est fausse sous réserve que le programme soit bien lancé dans un mode où les assertions sont vérifiées. En effet, la vérification des assertions n'est pas le mode par défaut : pour que les assertions soient vérifiées il faut lancer la machine virtuelle (le programme java) avec l'option -enableassertions (ou -ea), sinon elles sont toutes ignorées afin de ne pas ralentir l'exécution du code. Comparé aux exceptions, il faut savoir que les assertions : sont destinées à effecteur des vérifications «de routine» de nature à détecter des bugs de programmation : il ne faut surtout pas les utiliser pour gérer autre chose, comme par exemple des erreurs de saisie de l'utilisateur, un fichier inaccessible,... toutes les anomalies qui ne sont pas liées à une mauvaise écriture du code doivent être gérées par des exceptions et pas des assertions ; sont conçues pour faciliter la mise au point des programmes (c'est pourquoi le dispositif est débrayable : une fois le programme débuggé on peut choisir de supprimer la vérification des assertions pour privilégier la vitesse sur la fiabilité) ; sont nettement plus simples à utiliser ; sont inactivées par défaut. Remarque Il est parfaitement possible de se passer complétement des assertions et utiliser uniquement les exceptions (y compris pour gérer la détection des bugs). L'inverse est faux : les exceptions sont un dispositif essentiel de Java qu'il est impératif de connaître et maîtriser ne serait-ce que pour pouvoir utiliser l'ensemble des classes prédéfinies on ne saurait donc s'en passer et n'utiliser que des assertions. 97

90 VIII - Entrées - Sorties VIII Catégories de flux et classes à connaître 99 Fiches pratiques (exemples) 101 Autres classes à connaître 107 A. Catégories de flux et classes à connaître 1. Les 4 grandes catégories de flux abstraits Quatre classes «abstraites» (non instanciables), très générales, pour prendre en charge : lecture / écriture et mode binaire / caractères : - en mode binaire classes abstraites InputStream et OutputStream - en mode caractères classes abstraites Reader et Writer Ces classes fournissent des méthodes de «bas niveaux» toujours disponibles : 1. en mode lecture : int read() : prochain élément du flux (ou -1 si «fin de flux») int read(byte[] buf) pour InputStream et int read(char[] buf) pour Reader long skip(long nb) : saute nb éléments void close() 2. en mode écriture : void write(int c) void write (byte[] / char[] buf) pour Writer : void write(string s) void flush() void close() Remarque En tant que «classes abstraites (cf. Classe abstraite p 133)», ces classes servent de modèles aux classes qui suivent ; toutes ces méthodes seront donc disponibles par la suite dès lors qu'on voudra lire/écrire des données très élémentaires (de nature caractères ou octets). Pour lire des données de nature différentes (chaînes de caractères, nombres, instance de classes,...) il conviendra d'utiliser d'autres classes de plus haut niveau (voir ci-après). 99

91 Attention Les méthodes read() ci-dessus sont «bloquantes» : si il n'y a rien à lire sans que l'on soit en fin de fichier alors le programme se bloque dans l'attente d'un prochain octet ou caractère (cela ne peut pas arriver lors d'une lecture de fichier sur disque dur mais peut survenir dans le cas d'une lecture sur le clavier ou sur une connexion réseau), auquel cas le prochain octet ou caractère sera automatiquement détecté et débloquera le read(), et le programme. Les méthodes int read(byte[] buf) et int read(chat[] buf) lisent au maximum buf.length octets ou caractères, et retournent le nombre d'éléments lus, ou -1 si fin de flux. 2. Principaux flux «concrets» Quatorze classes de «bas niveau» déclinent les quatre classes précédentes selon l'origine ou la destination des données : lecture/écriture (séquentielle) dans fichiers : - en mode binaire : FileInputStream et FileOutputStream - en mode caractères : FileReader et FileWriter NOTA-BENE : nom du fichier en paramètre du constructeur lecture/écriture dans tableau en mémoire : - en mode binaire : ByteArrayInput(/Output)Stream - en mode caractères : CharArrayReader et CharArrayWriter NOTA-BENE : tableau en paramètre du constructeur lecture/écriture dans une chaîne : - en mode caractères : StringReader et StringWriter NOTA-BENE : chaîne en paramètre du constructeur enchaînements de flux («pipes») : - en mode binaire : PipedInputStream et PipedOutputstream - en mode caractères : PipedReader et PipedWriter 100

92 Entrées - Sorties 3. Conversions pour flux binaire Pour lire/écrire autre chose que des octets ou des tableaux d'octets, on utilise des classes de plus haut niveau (classes qui fournissent des méthodes plus puissantes que celles vues précédemment) : 1. Pour lire/écrire des types primitifs sous forme binaire classes DataInputStream / DataOutputStream : création à partir d'un flux d'octets : new DataOutputStream(outStream)... méthodes de lecture pour les types de base : readfloat(), readint(),... et idem en écriture : writefloat(x), writeint(i), Pour lire/écrire des objets sous forme binaire classes ObjectInputStream / ObjectOutputStream : création à partir d'un flux d'octets : new ObjectOutputStream(outStream)... mêmes méthodes que DataXXXStream + Object readobject() // (resp. writeobject(o)) les objets doivent être d'une classe implantant l'interface Serializable (cf. Interfaces Serializable, Externalizable et mot-clé transient p 143) 4. Autres conversions de flux Flux «avec tampon» (pour éviter des accès disque ou réseau à chaque lecture/écriture) : classes BufferedInputStream / BufferedOutputStream classes BufferedReader / BufferredWriter Flux pour écriture formatée en mode texte (comme pratiqué sur System.out) : classe PrintWriter fournit les méthodes : print(), println(), printf()... Flux compressés : paquetage java.util.zip classes ZipInputStream / ZipOutputStream Conversion flux octets / flux caractères : classes InputStreamReader / OutputStreamWriter B. Fiches pratiques (exemples) 1. En pratique : écriture d'un fichier «texte» 1. Importer les classes nécessaires : import java.io.*; 2. Ouvrir un flux de caractères vers un fichier : PrintWriter out = new PrintWriter("nomFichier"); idem en mode «concaténation» : PrintWriter out = new PrintWriter(new FileOutputStream("nomFichier", true)); idem en mode «auto-flush» (sans concaténation) : PrintWriter out = new PrintWriter("nomFichier", true); 3. Ecrire les caractères et/ou chaînes de caractères sur ce flux : out.print(ch); // avec ch : char ou String out.println(ch); // avec ch : char ou String 4. Fermeture du flux : out.close(); Remarque : chaque étape (sauf l'import) est susceptible de lancer une IOException donc mettre les instructions à risque dans un bloc try/catch (ou bien, utiliser une clause throws) 101

93 Exemple fichier : Ecriture de deux lignes de texte dans un import java.io.*; // double x = 5.72, y = -1.5; // try { PrintWriter out = new PrintWriter("f.txt"); out.println("x vaut : " + x); out.println("y vaut : " + y); out.close(); catch (FileNotFoundException e) { System.err.println("f.txt ne peut pas être ouvert"); catch (IOException e) { System.err.println("erreur d'entrée-sortie"); Complément : Les méthodes close() et flush() Dans l'exemple ci-dessus, il ne faut pas oublier le out.close() sinon les caractères risquent de ne pas être physiquement écrits sur le fichier par exemple si le programme a un bug et plante peu après la série de print(). Il faut en effet se souvenir que les écritures sur disque dur ne se font ni instantanément ni de manière synchrone avec les instructions de type print(). Pour des raisons d'efficacité, les lectures et écritures sont généralement «bufférisées» à au moins un niveau parmi machine virtuelle Java, système d'exploitation et/ou contrôleur du disque. Seul un appel à flush() ou close() garantit que les données précédemment bufferisées au niveau de la machine virtuelle ont bien été transmises au système d'exploitation et que ce dernier a reçu l'ordre de les inscrire sans délais sur fichier (ce qui ne garantit pas formellement que l'écriture aura bien lieu mais en pratique cela conduit à une écriture immédiate sauf soucis au niveau du matériel). REMARQUE : lors de la création d'un PrintWriter on peut demander via l'option «auto-flush» à ce qu'un appel à flush() soit systématiquement exécuté après chaque appel à println(), printf() ou format(). Aussi, l'effet de out.close() est multiple : il exécute flush()sur le flux out ; puis libère les ressources allouées au niveau de la machine virtuelle et du système d'exploitation. NOTA-BENE : sauf terminaison prématurée du programme, tous les flux ouverts sont automatiquement fermées à la fin de chaque programme : le close() n'est donc pas strictement nécessaire en théorie, mais en pratique il est important pour se protéger d'un risque de plantage du programme, et aussi pour synchroniser le code avec le contenu d'un fichier ce qui peut-être essentiel si le fichier est accédé par ailleurs depuis un autre programme, ou pour faciliter le debugage du code. 102

94 Entrées - Sorties 2. En pratique : lecture d'un fichier «texte» sans Scanner 1. Importer les classes nécessaires : import java.io.*; 2. Ouvrir un flux de caractères depuis un fichier : FileReader in = new FileReader("nomFichier"); 3. Lire caractère par caractère sur ce flux : ch = in.read(); // ch vaut -1 en fin de fichier 4. Fermeture du flux : in.close(); Remarques : Chaque étape (sauf l'import) peut lancer une IOException bloc try/catch (ou throws). Pour lire des nombres ou toutes données structurées écrites sous forme texte, utiliser la classe Scanner (voir exemple suivant) Exemple fichier : Comptage du nombre de lettres 'A' d'un import java.io.*; // int n = 0; // try { FileReader in = new FileReader("f.txt"); while ( ( ch = in.read() )!= -1 ) { if (ch == 'A') n++; in.close(); catch (FileNotFoundException e) { System.err.println("f.txt ne peut pas être ouvert"); catch (IOException e) { System.err.println("erreur d'entrée-sortie"); 3. En pratique : lecture d'un fichier «texte» avec Scanner 1. Importer les classes nécessaires : import java.io.*; import java.util.scanner; 2. Ouvrir un flux de caractères depuis un fichier : FileReader in = new FileReader("nomFichier"); 3. Créer un scanner branché sur ce flux : Scanner sc = new Scanner(in); 4. Lire une ligne entière via ce Scanner : String l = sc.nextline(); 5. Tester la présence d'un double, et le lire si présent : if( sc.hasnextdouble() ) { double val = sc.nextdouble(); 6. Fermeture du flux : in.close(); 103

95 Remarque : chaque étape (sauf l'import) peut lancer une IOException try/catch (ou throws) bloc Exemple : Lecture d'un fichier comportant une suite de nombres entiers, et calcul de leur somme import java.io.*; import java.util.scanner; // int somme = 0; try { FileReader in = new FileReader("f.txt"); Scanner sc = new Scanner(in); while (sc.hasnextint()) { somme += sc.nextint(); in.close(); catch (FileNotFoundException e) { System.err.println("f.txt n'existe pas"); catch (IOException e) { System.err.println("erreur d'entrée-sortie"); Complément Dans l'exemple ci-dessus il faut que le fichier comporte uniquement des entiers et des séparateurs (blancs, passages à la ligne,...) sinon la lecture du fichier et le calcul de la somme s'arrête avec le premier élément invalide (lettre, ponctuation,...) dans la mesure où sc.hasnextint() retourne faux si le prochain élément à lire sur le flux ne peut pas être considéré comme un entier écrit en base 10. Dans la variante ci-dessous, le code a été «amélioré» pour faire la somme de tous les entiers d'un fichier, quelque soit ce qu'il contient par ailleurs. On y utilise toujours un scanner mais, à chaque tour de boucle, on commence par vérifier qu'il reste quelque chose à lire par sc.hasnext() avant de lire l'élément suivant en distinguant selon sa nature (entier ou pas). import java.io.*; import java.util.scanner; // int somme = 0; try { FileReader in = new FileReader("f.txt"); Scanner sc = new Scanner(in); while (sc.hasnext()) { if (sc.hasnextint()) { somme += sc.nextint(); else { sc.next(); in.close(); 104

96 Entrées - Sorties catch (FileNotFoundException e) { System.err.println("f.txt n'existe pas"); catch (IOException e) { System.err.println("erreur d'entrée-sortie"); 4. En pratique : écriture d'un fichier «binaire» 1. Importer : import java.io.*; 2. Ouvrir un flux d'octets vers un fichier : FileOutputStream out = new FileOutputStream("nomFichier"); 3. Brancher un flux d'écriture d'objets sur le flux d'octets : ObjectOutputStream objout = new ObjectOutputStream(out); 4. Ecrire les nombres et/ou objets sur ce flux : objout.writeint(i); // i nb. entier objout.writedouble(x); // x nb. flottant //... objout.writeobject(o); // o objet d'une classe qui implante l'interface Serializable 5. Fermeture des flux : objout.close(); Remarque : chaque étape (sauf l'import) peut lancer une IOException try/catch (ou clause throws) Exemple : un fichier bloc Ecriture d'un objet (en mode binaire) dans import java.io.*; // Auteur a, b; // try { FileOutputStream out = new FileOutputStream("f.bin"); ObjectOutputStream objout = new ObjectOutputStream(out); objout.writeobject(a); objout.writeobject(b); b.modifier(...); // attributs de b modifiés objout.reset(); // indispensable ici voir remarque! objout.writeobject(b); objout.close(); catch (FileNotFoundException e) { System.err.println("f.bin ne peut pas être ouvert"); catch (IOException e) { System.err.println("erreur d'entrée-sortie"); Remarque : la méthode reset() Lorsqu'une même instance est passée en paramètre à writeobject() à plusieurs reprises, il faut impérativement invoquer la méthode reset() sur le flux comme dans l'exemple ci-dessus (sinon, c'est la version initiale de l'instance qui est écrite à nouveau sur le flux). 105

97 Complément : Sérialisation / désérialisation On appelle sérialisation ou linéarisation (en anglais serialization ou marshalling) l'opération consistant à transformer des données en mémoire vive (d'essence possiblement complexe telles qu'un arbre ou un graphe) en une série d'octets en vu, typiquement, d'une sauvegarde sur fichier ou d'une transmission par connexion réseau. L'opération inverse s'appelle désérialisation. Dans le cadre d'un langage objet, il est ainsi fréquemment nécessaire de la sérialiser / désérialiser des objets (instances des classes). Or, ce n'est pas une tâche triviale dans le cas général dans la mesure où : 1. les données «propres» à un objet (celles qu'il convient de sauvegarder si on veut pouvoir re-créer ensuite l'objet) se compose de l'ensemble de ses attributs non-statiques, ainsi que ceux de sa classe mère (et récursivement jusqu'à la classe racine) 2. chaque attribut dont la nature est «référence non-nulle» pointe soit sur un tableau, soit sur objet, qu'il convient donc de sérialiser également. Le tout forme un graphe avec possibilités de cycles. 3. en cas de sauvegarde sur fichier, il faut anticiper le problème que posera la modification du programme entre l'instant où des données sont sérialisées et celui où l'on cherchera à les relire pour recréer un objet : rien n'interdit que la définition des classes correspondants aux objets sauvegardées ait été modifiée, par exemple via l'ajout ou la suppression d'un attribut. Pour simplifier le travail des programmeurs (et dans le même temps améliorer la fiabilité des programmes), Java inclut en standard un mécanisme de sérialisation / désérialisation capable de fonctionner automatiquement sur n'importe quel objet de n'importe quelle classe, et pas seulement les classes prédéfinies. C'est bien sur ce mécanisme qui est mis en œuvre de manière transparente par les méthode writeobject() et readobject() sous réserve que la classe «implante l'interface Serializable» (cf. Interfaces Serializable, Externalizable et mot-clé transient p 143). 5. En pratique : lecture d'un fichier «binaire» 1. Importer : import java.io.*; 2. Ouvrir un flux d'octets depuis un fichier : FileInputStream in = new FileInputStream("nomFichier"); 3. Brancher un flux de lecture d'objets et de données sur le flux d'octets : ObjectInputStream objin = new ObjectInputStream(in); 4. Lire les nombres et/ou objets sur ce flux : int i = objin.readint(); double x = objin.readdouble(); //... Object o = objin.readobject(); 5. Fermeture des flux : objin.close(); Remarques : chaque étape (sauf l'import) peut lancer une IOException (ou throws) 106 bloc try/catch la méthode readobject() peut en outre lancer d'autres exceptions penser à convertir ce que retourne readobject() dans le bon type (celui de l'objet écrit à cet endroit du fichier)

98 Entrées - Sorties Exemple : un fichier Lecture d'un objet (en mode binaire) depuis import java.io.*; // Auteur a; // try { FileInputStream in = new FileInputStream("f.bin"); ObjectInputStream objin = new ObjectInputStream(in); a = (Auteur) objin.readobject(); objin.close(); catch (FileNotFoundException e) { System.err.println("f.bin ne peut pas être ouvert"); catch (IOException e) { System.err.println("erreur d'entrée-sortie"); Remarque Il peut être utile de connaître davantage de détails sur le fonctionnement des méthodes readobject() et writeobject(), surtout lorsqu'on ne se satisfait pas du comportement par défaut consistant à lire/écrire tous les attributs de la classe : voir plus loin pour un complément à ce propos nécessitant d'avoir déjà vu les notions d'héritage et d'interfaces (cf. Interfaces Serializable, Externalizable et mot-clé transient p 143). C. Autres classes à connaître 1. Entrées-sorties en mode «random» RandomAccessFile : classe permettant des lectures/écritures simultanées, et aussi des lectures/écritures non-séquentielles constructeur : RandomAccessFile(filename,mode) mode valant "r" (readonly) ou "rw" (read/write) écrire sur le fichier : - raf.writeint(i); // i entier - raf.writefloat(x); // x flottant - raf.writeutf(s); //... // s String lire sur le fichier : - int i = raf.readint(); - float x = raf.readfloat(); - String s = raf.readutf(); - String l = raf.readline(); //... taille : int len = raf.length() déplacement dans le fichier : raf.seek(pos); 107

99 2. Manipulation de fichiers et répertoires File : classe pour manipuler fichiers/répertoires (accès à la taille, listage du contenu, suppression, renommage,...) constructeurs : - File(String name) - File(String path, String name) -... méthodes : - boolean exists() - long length() - File getparent() - boolean isdirectory() - String[] list() - void delete() - void mkdir(), - boolean renameto(file f)

100 Listes, piles, files, arbres IX - IX Problématique commune 109 Listes 110 Piles 113 Files 116 Arbres 117 A. Problématique commune Trouver une structure de données qui permette de représenter en mémoire, et manipuler, efficacement une suite d'éléments de même type. En pratique, il s'agit de satisfaire simultanément un maximum d'objectifs parmi : minimiser l'occupation en mémoire ; minimiser le temps d'accès en moyenne et/ou au pire lors de l'accès à un élément (pour le modifier par exemple) ; idem pour les autres opérations élémentaires usuelles : ajout, suppression, recherche d'un élément ; idem pour les opérations portant sur la totalité des éléments : parcours, tri, vidage, remplissage aléatoire, Atteindre tous ces objectifs à la fois est impossible en général. Le mieux que l'on puisse faire consiste à choisir la «meilleure» structure de données dans un contexte donné, c'est-à-dire celle qui présente le compromis optimal lorsque l'on tient compte : 1. de la nature des éléments à manipuler ; 2. de l'application à réaliser, chaque application se caractérisant par une distribution différente dans la fréquence relative des opérations ci-dessus. Aussi, il est important de bien connaître les structures de données classiques que sont les listes, piles, files et arbres (et pour chacune de comprendre les différentes implantations possibles) afin de savoir bien choisir la combinaison type abstrait implantation la mieux adaptée à la résolution d'un problème donné. 109

101 Exemple Un tableau d'entier conviendrait-il pour ranger efficacement des entiers dans l'ordre croissant? B. Listes 1. Introduction Une liste est une suite finie de N+1 couples (ai, pi) E P {null telle que : (ai, pi ) s'appelle un maillon E est l'ensemble des éléments ai P est l'ensemble des positions pi valeur ((ai, pi)) = ai E position (a0, p0) = premier P position ((ai, pi)) = pi -1 P i > 0 pn = null P Une liste sera donc définie par : les N éléments ai premier P : la position du premier maillon une bijection «successeur» de P dans P telle que : successeur(pi ) = pi + 1 Attention Une liste est ordonnée par la fonction de succession (rang = n ième maillon de la liste), mais la position peut n'avoir aucun rapport avec cet ordre. 110

102 Listes, piles, files, arbres 2. Fonctions de manipulation Les accesseurs renvoient des positions de maillons Les transformateurs modifient une liste (peuvent éventuellement renvoyer une liste modifiée) Les observateurs renvoient des renseignements divers Exemple : Exemples d'accesseurs : renvoyerlepremierdelaliste : liste position renvoyerledernierdelaliste : liste position donnerposition : liste, rang position donnerpositionsuivant : liste, position position donnerpositionprécédent : liste, position position Exemple : Exemples de transformateurs : Peuvent changer la liste ou en restituer une autre modifiée creerliste : liste ajouterdernier : liste, élément liste enleverdernier : liste liste ou inserer : liste, élément, rang liste supprimer : liste, rang liste ou Exemple : Exemples d'observateurs : longueurdelaliste : liste entier estvide : liste booléen rechercher : liste, élément entier (1er rang trouvé) valeur : liste, position élément imprimertout : liste imprimer : liste, rangdébut, rangfin 111

103 3. Implantation Implantation statique par tableau Les éléments sont placés dans les cases d'un tableau la position est définie par l'index dans le tableau (ai, pi) = (t[i], i + 1) Avantages Accès direct à l'élément par l'indice Inconvénients Insertion, suppression, ajouts délicats Taille maximum fixée à l'avance Implantation statique par tableau chaîné Les éléments sont placés dans les cases d'un tableau dans l'ordre de leur création la position (indice) est définie dans un autre tableau (ou dans une nouvelle dimension du tableau) (ai, pi) = (t[i], p[i]) Avantages Accès semi-direct à l'élément par l'indice Réarrangement facile Inconvénients Taille maximum fixée à l'avance Comment ajouter rf? 112

104 Listes, piles, files, arbres Implantation dynamique par références chaînées Les éléments sont placés au fur et à mesure dans une place mémoire qu'on alloue à leur création la place réservée en mémoire contient un maillon, c'est à dire l'élément ai,, et la référence pi du maillon suivant (ai, pi) Avantages Taille maximum non fixée à l'avance, occupation mémoire optimale (si on néglige l'espace occupé par les références vers les maillons suivants) Réarrangement facile Inconvénients Parcours séquentiel obligatoire pour accéder à un élément 4. Applications Liste ordonnée pour ranger des éléments suivant un ordre prédéfini (insertion, suppression) augmente le temps d'insertion d'un nouvel élément diminue le temps de restitution (évite un tri) Ex : répertoire alphabétique, actions datées, catalogue de références, Pile et File pour simplifier à l'extrême le jeu d'instructions Pile : on met et retire un élément uniquement en fin de liste File : on ajoute les éléments en fin de liste, on les retire en début de liste C. Piles 1. Introduction Une pile est une liste à accès restreint, c'est une suite d'éléments accessible uniquement par le sommet Une pile est une liste de type «LIFO» (Last In First Out) Fonctions essentielles d'une pile: Créer une pile Empiler un maillon Dépiler un maillon Obtenir l'élément «sommet» (peut-être combiné à «dépiler») Vérifier si la pile est vide 113

105 2. Fonctions de manipulation Si E est l'ensemble des éléments et P l'ensemble des piles, les fonctions d'accès à une pile sont : méthode arguments creer() retour action P renvoie pile vide une sommet() P E renvoie l'élément situé au sommet empiler(e) PxE P renvoie une pile à laquelle on a ajouté l'élément e au sommet dépiler() si pile non vide P P renvoie une pile à laquelle on a enlevé le sommet (ou ) estvide() P B renvoie un booléen : vrai si la pile est vide, faux sinon Selon la manière d'implanter une pile, on peut modifier le type, ou les arguments de ces fonctions. (par ex : dépiler() peut renvoyer le sommet et pas la pile) 3. Piles : implantation 114 Selon l'utilisation souhaitée, on peut implanter une pile par tableau statique ou chaîné ou par allocation dynamique de mémoire. Tableau : dans le cas d'un tableau simple, il faut un tableau de N éléments et un entier désignant le sommet courant. Attention, la taille est fixée, d'où la gestion nécessaire d'un dépassement (pile pleine) Chaînage : il faut soit utiliser un tableau chaîné (statique), soit considérer une structure maillon qui contient la partie «élément», et une référence au maillon suivant (dynamique)

106 Listes, piles, files, arbres 4. Application La pile (stack) est beaucoup utilisée en programmation (pile d'appels, pile d'erreurs). La gestion de la récursivité fait généralement appel à une pile. Certaines calculettes utilisent la notion de pile pour éviter la gestion des parenthèses. Exemple d'utilisation d'une pile : gestion de la pile d'appels d'une fonction récursive public static long factorielle(long n) { if (n==1) { return 1L ; else { return n*factorielle(n-1); 115

107 D. Files 1. Introduction Une file est une liste à accès restreint ; c'est une suite d'éléments accessible par le sommet en entrée, par la base en sortie Une file est une liste de type «FIFO» (First In First Out) Fonctions essentielles d'une file: Créer une file Ajouter un maillon (au sommet) Retirer un maillon (à la base) Vérifier si la file est vide 2. Fonctions de manipulation Si E est l'ensemble des éléments et F l'ensemble des files, les fonctions d'accès à une file sont : méthode arguments creer() 116 retour action F renvoie une file vide ajouter(e) FxE F renvoie une file à laquelle on a ajouté l'élément e au sommet enlever() F FxE renvoie une file à laquelle on a enlevé la base (ou ) estvide() F B renvoie un booléen : vrai si la pile est vide, faux sinon Selon la manière d'implanter une file, on peut modifier le type, ou les arguments de ces fonctions. (par ex : enlever() peut renvoyer le sommet et pas la file)

108 Listes, piles, files, arbres 3. Implantation Seule une implantation de type «chaînée» convient pour une file. L'implantation en tableau simple nécessiterait de réorganiser le tableau à chaque suppression 4. Applications Les files sont souvent utilisées pour gérer «l'attente». Les files d'attente d'impressions, les buffers sont autant de files Buffer stdin (clavier) - Saisie au clavier de : «ls -l tp3» E. Arbres 1. Introduction Structure d'arbre Un arbre est une extension de la notion de liste dans laquelle un maillon peut avoir plusieurs suivants. C'est donc une suite d'éléments qui ont chacun 0, 1, ou plusieurs suivants. En conséquence, il y a plusieurs façon de définir un ordre, c'est à dire le «rang» d'un élément. 2. Récursivité Un arbre peut toujours être considéré d'une manière récursive par sa racine et un ensemble d'arbres liés à cette racine (les sous-arbres). 117

109 3. Vocabulaire ««««««««««««««racine», «feuilles» nœud», «branche» fils», «père», «frères» ascendants» descendants» arc», «chemin» sous-arbre» niveau» profondeur» forêt» complet» dégénéré» général» binaire» 4. Arbres binaires Un arbre binaire, est une arbre général dont les nœuds ne peuvent avoir plus de 2 fils. En pratique, il existe une équivalence entre arbre général et arbre binaire. 5. Numérotation des nœuds Deux façons de numéroter (ordonner) les nœuds d'un arbre (et parmi elles, plusieurs variantes possibles) : 118

110 Listes, piles, files, arbres 6. Parcours Dans une numérotation dynastique, on distingue essentiellement 3 modes de parcours d'un arbre binaire - selon la position de la racine dans le parcours (récursivité): Le parcours R G D dit parcours préfixé. Le parcours G R D dit parcours infixé. Le parcours G D R dit parcours postfixé. 7. Exemple de parcours RGD en java Fonction récursive effectuant un parcours RGD d'un arbre pour l'imprimer : void afficherrgd() { if (!(estvide())) { imprimeracine(); gauche.afficherrgd(); droit.afficherrgd(); else { imprimervide(); 8. Fonctions de manipulation d'arbres binaires Si E est l'ensemble des éléments et A l'ensemble des arbres binaires, ci dessous quelques exemples de fonctions applicables aux arbres binaires: creer() A A renvoie un arbre vide racine() AxA E renvoie l'élément racine ajouteg(a) (resp. ajouted(a)) A A ajoute/remplace le sous arbre gauche (resp. droit) par un arbre a enleveg() (resp. enleved(a)) A A renvoie l'arbre amputé du sous arbre gauche (resp. droit) gauche() (resp. droit(a)) A A envoie le sous arbre gauche (resp. droit) ou estvide() A B renvoie le booléen vrai si l'arbre est vide, faux sinon Attention : avec la notion d'arbre, il faut toujours penser«récursivité» 119

111 9. Implantation Par Chaînage : Il faut considérer une structure récursive qui contient, à chaque niveau : la partie «élément» (racine) Des références aux sous arbres comme - par exemple - une liste de sousarbres Dans le cas d'un arbre binaire : - une référence à un arbre : le sous arbre gauche - une référence à un arbre : le sous arbre droit Par Tableau : Il faudrait un tableau de N éléments et (pour un arbre binaire) deux tableaux de N entiers pour représenter les indices (dans le tableau) des fils à gauche et à et droite. Très peu utilisé par sa structure figée et les «trous» laissés lorsque l'arbre n'est pas complet. 10. Applications Gestion syntaxique d'une expression logique parenthésée Principe : Si opérateur alors on crée un sous-arbre dont l'opérateur est la racine Sinon (opérande) on crée une feuille Le parcours parcours préfixé ( R G D ) ou «notation polonaise» donnera l'expression : /*+abc*a+bc Le parcours infixé ( G R D ) donnera l'expression : a + b * c / a * b + c, PAS CONVENABLE ici car revient à retirer les parenthèses parcours G D R Le parcours postfixé ( G D R ) ou «notation polonaise inverse» donnera l'expression ab+c*abc+*/ 120

112 Listes, piles, files, arbres Arbres Binaires de Recherche Représentation de données en vue d'une utilisation ordonnée Principe : rangement au fur et à mesure : à gauche si «avant», à droite sinon Le parcours GRD donne les éléments en ordre alphabétique (DRG en ordre alphabétique inversé) 121

113 Paquetages, importation X- X Paquetage 123 Paquetage et visibilité 123 Importation 124 Nommage des paquetages 124 Organisation en fichiers, compilation et exécution 124 Paquetages standards de Java 125 A. Paquetage Entité de structuration regroupant plusieurs classes et/ou interfaces et/ou souspaquetages Les packages définissent des espaces de nommage (ou namespace) distincts (réduit les risques de conflits dans les noms de classes) Le paquetage d'appartenance est indiqué au début du fichier source par : package nompackage; Les fichiers.class de chaque paquetage doivent impérativement être placés dans un répertoire ayant le nom exact du paquetage Les paquetages (et classes) sont recherchés dans une liste de répertoires (et/ou de fichiers zip) fixée par la variable d'environnement : CLASSPATH Attention Par défaut (lorsque le mot-clé package est omis en début de fichier) les classes et interfaces sont définis dans le «paquetage anonyme» à éviter, sauf pour de petits programmes. B. Paquetage et visibilité Par défaut, les classes et interfaces ne sont visibles que dans le paquetage où elles sont définies seules celles qui sont déclarées «publiques» pourront être importées dans d'autres paquetages. Exemple : public class Cercle { // classe visible dans son package // et dans tous les packages qui l'importent 123

114 class Auxiliaire { // classe visible dans son package uniquement // (pas de possibilité de l'importer) Par défaut, les attributs et méthodes sont visibles dans tout le paquetage de la classe où ils sont définis (et nulle part ailleurs). Les mots-clés public, protected et private appliqués aux attributs et méthodes permettent de modifier la visibilité «paquetage» par défaut. C. Importation Pour utiliser une classe (publique) C à l'extérieur de son package P : la désigner par son nom complet : P.C ou alors l'importer en début de fichier par : import P.C; puis la désigner par son nom court : C Possibilité d'importer toutes les classes publiques d'un package P par : import P.*; Autre possibilité : importer uniquement certains attributs et/ou méthodes statiques d'une classe (publique), exemple : import static java.lang.math.pi; // permet d'écrire plus loin dans le fichier : // double d = 2 * PI; NOTA-BENE : importer des attributs et/ou méthodes non-statiques n'est pas possible (cela n'aurait guère de sens). Conseil L'importation statique doit être utilisée avec parcimonie (le système de nommage par défaut de Java est conçu pour faciliter l'écriture de grands programmes en évitant les conflits de noms, y compris lorsque le code évolue dans le temps). On évitera en particulier d'utiliser le caractère * pour importer tous les attributs et méthodes statiques d'une classe, sauf à la rigueur pour les classes les plus connues de Java telles que java.lang.math. D. Nommage des paquetages Attention au nommage des paquetages : choisir un nom clair, concis et qui, néanmoins, minimise tout risque de conflit de nom (présent ou futur) Usage en Java le nommage de style «hostname inversé», exemple : fr.institution.service.nom_paquetage E. Organisation en fichiers, compilation et exécution Au maximum une classe ou interface publique par fichier source (auquel cas, le nom du fichier doit impérativement être celui de la classe ou interface publique contenue dans le fichier) Il peut y avoir d'autres classes et interfaces non publiques dans le même fichier La compilation du fichier f.java produit autant de fichiers (suffixés par.class) qu'il y a de classes dans le fichier f.java Exécution (à partir d'un terminal) du main de la classe C située dans le package P : 124

115 Paquetages, importation - depuis le répertoire du package P : java C - depuis le répertoire parent : java P.C F. Paquetages standards de Java Nombreux paquetages «standards» en Java classes toujours disponibles (sous réserve de les importer) quels que soient la machine, l'os,... Quelques packages standards parmi les plus utilisés : java.lang : classes de base du langage java.util : classes utilitaires, structures de données,... java.io : classes liées aux entrées-sorties java.math : calculs en précision arbitraire java.text : internationalisation java.awt : graphisme (Abstract Window Toolkit) java.applet : appliquettes javax.swing : graphisme «2ème génération» java.sql : bases de données (JDBC) java.security : cryptage, authentification, Complément : les «compacts» Il est possible en Java de se limiter volontairement à un sous-ensemble du langage afin de réduire la taille de la machine virtuelle nécessaire à l'exécution du code (utile pour exécuter du code Java sur des machines disposant de peu de mémoire). Java définit ainsi trois sous-ensembles dénommés «compact 1», «compact 2» et «compact 3» qui se différencient par les paquetages accessibles. Conseil Penser à la documentation en-ligne de Java pour approfondir tel ou tel paquetage, voir aussi les nombreux tutoriaux disponibles (cf. Annexe : ressources complémentaires sur Java p 219). 125

116 Compléments sur les classes XI - XI Niveaux de visibilité 127 Classes ou interfaces internes 128 Classes locales et classes anonymes 128 Héritage, classe racine, Introspection 137 A. Niveaux de visibilité Objectif : sécuriser l'écriture des programmes composés d'un grand nombre de classes. Quatre niveaux de visibilité en Java pour les attributs et méthodes : - private : accessible seulement depuis l'intérieur de la classe - package : accessible seulement depuis le même package (visibilité par défaut) - protected : idem + depuis les classes dérivées même situées dans un autre package - public : accessible partout Deux niveaux de visibilité pour les classes et interfaces : - package : accessible seulement depuis le même package (visibilité par défaut) - public : accessible partout Trois mots-clés : private, protected et public (package est la visibilité par défaut en l'absence de qualificatif) Voir les règles de bon usage dans le chapitre sur les classes (cf. Visibilité p 88). 127

117 Exemple class Employe { private String nom; protected int age; protected int salaire; public tostring() {... double calculerprime() {... //... public class MonProgramme { //... Employe e = new Employe(... ); // OK ssi même package String s = e.tostring(); // OK (public) double prime = e.calculerprime(); // OK ssi même package e.age++ ; // OK ssi même package (protected) int x = e.salaire ; // OK ssi même package (protected) e.nom = "Durand"; // ERREUR (private) //... Complément La visibilité «protected» n'a de sens spécifique que lorsqu'une (au moins) des classes filles est située dans un package différent. B. Classes ou interfaces internes Une classe «interne» (ou «nichée») est une classe définie à l'intérieur d'une autre (au même niveau que attributs/méthodes) Idem pour les interfaces «internes» (ou «nichées») Intérêt : classes (ou interfaces) utilitaires très liées à classe englobante Pour les classes internes, 2 catégories : - static : classes «normales» mais fortement liées à la classe englobante - membres : associées à chaque instance ; peuvent accéder directement aux attributs privés de classe englobante C. Classes locales et classes anonymes Une classe «locale» est une classe définie à l'intérieur du corps d'une méthode Une classe locale ne peut pas être statique Classe anonyme = classe locale sans nom, définie juste à l'intérieur d'un new Usage possible : pour créer une instance unique d'une classe très particulière ou bien une implantation ad hoc d'une interface (i.e. gestionnaires d'événements (cf. Événements et programmation événementielle p 186)) 128

118 Compléments sur les classes D. Héritage, classe racine, Notion de hiérarchie de classes 2. Héritage Intérêt de l'héritage : réutiliser une classe existante en l'adaptant ; créer des variantes d'une classe ;... Mot-clef : extends class Figure { private String nom; private Position pos; public Figure(Position p){ pos = p; public void deplacer(int dx, int dy) { pos.ajouter(dx, dy); class Cercle extends Figure { // Un cercle est un cas particulier de Figure, // la classe Cercle hérite de tous les // attributs et méthodes le la classe Figure //... En Java, héritage simple uniquement (pas plus d'une classe mère) 129

119 3. Héritage, attributs et méthodes Une sous-classe (ou classe fille ou classe dérivée) hérite de tous les attributs et méthodes (y compris statiques) de sa super-classe (ou classe mère) : Cercle c = new Cercle(); // appel d'une méthode héritée c.deplacer(2, -1); Une sous-classe peut évidemment définir supplémentaires qui lui sont spécifiques : des attributs et méthodes class Cercle extends Figure { private double rayon; public double circonference() { return 2*Math.PI*rayon; 4. Héritage et visibilité Une classe fille ne peut accéder qu'aux attributs et méthodes «public» ou «protected» de sa classe mère (ainsi qu'aux attributs et méthodes «package» ssi elle appartient au même paquetage que sa classe mère) : class Cercle extends Figure { //... void essai() { // essai d'accès à un attribut privé // de la classe mère : String s = nom; // ERREUR! 5. Héritage et références Toute référence vers une instance de la classe fille peut être vue aussi comme une référence vers la classe mère (conversion automatique fille mère) : Figure f = new Cercle(); // OK : affectation d un Cercle dans une Figure Cercle c = new Cercle(1); if ( f.contient(c) ) { // OK : passage d un Cercle en paramètre // à une méthode attendant une Figure ATTENTION : l'opération inverse est interdite : Cercle c = new Figure(); // Interdit! // On doit respecter le sens de l'héritage // y compris dans sa signification // «est un cas particulier de» 130

120 Compléments sur les classes Complément : instanceof et héritage Il est possible (et recommandé) d'utiliser le mot-clé instanceof pour distinguer les instances de différentes sous-classes à partir d'une référence dont le type est celui de leur classe mère. Exemple : étant données - une classe Figure dont hérite plusieurs sous-classes : Triangle, Cercle,... - une référence f de type Figure alors f instanceof Cercle retourne vrai ssi f réfère spécifiquement un objet de type Cercle (et pas un objet d'une autre sous-classe de Figure). 6. Héritage et constructeurs Les constructeurs ne sont pas hérités, mais on peut appeler ceux de la classe mère avec super(...) : class Cercle extends Figure { //... Cercle(float r, Position pos) { super(pos); // appel du constructeur Figure(pos) rayon = r; NOTA-BENE : l'appel super(...) doit impérativement être la 1ère instruction du constructeur si la 1ère instruction n'appelle ni le constructeur de la classe mère, ni un autre constructeur de la classe fille, alors il y a appel automatique de super() sans argument ordre des opérations : 1/ appel du constructeur de la classe mère 2/ initialiseurs et blocs d'initialisation 3/ corps du constructeur fille 7. Redéfinition, spécialisation, masquage Méthodes et attributs héritées peuvent être redéfinis dans les classes filles, mais le vocabulaire et les conséquences différent : pour les méthodes non-statiques : on parle de «spécialisation» (en anglais : overriding) = possibilité de définir un comportement spécifique pour les opérations héritées (en définissant une méthode ayant exactement la même «signature» mais un code différent) pour les attributs : la redéfinition est possible (y compris avec un typage différent que dans la classe mère) mais rarement pertinente pour les méthodes statiques : la redéfinition est possible mais rarement pertinente Dans les trois cas, il y a alors «masquage» de l'attribut ou méthode hérité En cas de masquage, le mot-clé super permet d'accéder si besoin aux attributs et méthodes de la classe mère rendus inaccessibles autrement (voir exemple) class Cercle extends Figure { 131

121 private float rayon; //... public void afficher() { // si besoin, appel de la méthode de même // nom dans la classe mère : super.afficher(); // traitement spécifique à la classe fille : System.out.println("rayon=" + rayon); Remarque La visibilité d'une méthode redéfinie peut être différente (mais seulement augmentée). En cas de masquage, c'est le type de la référence qui détermine quel attribut est pris en compte par défaut entre celui de la classe fille et celui héritée mais masqué. Il est possible d'accéder à un attribut (mais pas à une méthode) masqué d'une classe ancêtre quelconque en utilisant la syntaxe : ((ClasseAncêtre) this).attributmasqué L'annotation (cf. Annotations p permet d'expliciter l'intention du programmeur de redéfinir une méthode héritée, syntaxe public void afficher() {... La redéfinition d'un attribut non-statique crée en pratique un 2 attribut pour chaque instance de la classe fille (Java alloue une zone mémoire supplémentaire et stocke les 2 valeurs). 8. Polymorphisme dynamique Quand on manipule un objet via une référence à une classe mère, ce sont toujours les méthodes (non statiques) de la classe effective de l'objet qui sont appelées : Figure f = new Cercle(); //... f.afficher(); // appel afficher() de Cercle bien que // f est une référence de type Figure! 9. Méthode abstraite Une méthode «abstraite» est une méthode dont on a spécifié la signature mais pas écrit le corps Mot-clef : abstract class Figure { //... public abstract void colorier(); Méthode destinée à être (re)définie dans les classes filles Ne peut exister que dans une classe elle-même déclarée abstraite (voir ci-après) Impossible pour les méthodes «statiques» 132

122 Compléments sur les classes 10. Classe abstraite Une classe «abstraite» est une classe non instanciable (elle sert uniquement de classe mère) Introduite par le mot-clef : abstract abstract class Figure { //... Toute classe qui contient au moins une méthode abstraite (ou qui en hérite une sans la redéfinir) doit obligatoirement être déclarée abstraite Remarque : constructeur(s) dans une classe abstraite Bien que non instanciable, une classe abstraite peut inclure un (ou plusieurs) constructeurs. Ces constructeurs ne pourront être invoqués que dans le cadre de l'instanciation d'une classe fille non-abstraite (via l'instruction super() en début du constructeur de la classe fille). Intérêt : initialiser les attributs définis au niveau de la classe abstraite ; factoriser les opérations à effectuer dans tous les cas lors de la création des instances des classes filles. 11. Classe non dérivable C'est une classe qui ne pourra pas servir de classe mère Mot-clef : final final class ClasseTerminale { //... Intérêt : sécuriser, fiabiliser le développement de gros programmes Exemple : beaucoup de classes du paquetage java.lang 12. Méthode non redéfinissable Il est possible en Java d'interdire la redéfinition d'une méthode dans les classes filles Mot-clef : final Exemple : abstract class Figure { Position pos; final public deplacer(int dx, int dy) { pos.ajouter(dx, dy); 133

123 13. Héritage et tableau Si une classe Fille dérive de Mere, alors Fille[] est considéré comme un «soustype»17 de Mere[]. Cela se traduit par le fait qu'un tableau d'instances de Fille sera autorisé partout où un tableau d'instances de Mere est attendu. Exemple : Fille[] tabf = new Fille[3]; Mere[] tabm = tabf; // OK //... // ATTENTION // même manipulé via un Mere[], // un tableau de Fille ne peut contenir // que des références à Fille : tabm[0] = new Mere(); // Erreur 14. la classe «Object» La classe Object est à la racine de l'arbre d'héritage des classes en Java ; elle est donc l'ancêtre de toutes les classes. La classe Object définit plusieurs méthodes héritées par toutes les classes (et applicables aussi aux tableaux) : boolean equals(object obj) par défaut, retourne this==obj (compare les références), mais conçue pour être redéfinie afin de comparer véritablement les contenus (ex : classe String) int hashcode() par défaut, retourne un entier raisonnablement utilisable dans une table de hashage (entier déduit de l'adresse mémoire de l'objet), conçue pour être redéfinie si besoin pour optimiser les performances du hashage String tostring() par défaut, retourne "NomClasse@"+hashCode(), mais conçue pour être redéfinie pour produire une représentation textuelle pertinente de l'objet finalize() par défaut, ne fait rien, mais conçue pour être redéfinie si besoin pour spécifier quoi faire lors de la destruction de l'objet avant de libérer la mémoire Object clone() : voir ci-après Class getclass() : voir ci-après notify(), notifyall(), wait() : voir le chapitre sur les Threads (cf. Synchronisation des exécutions p 210) NOTA-BENE : les méthodes getclass(), notify(), notifyall(), wait() sont déclarées «final» dans la classe Object et ne peuvent donc pas être redéfinies ; les autres peuvent et doivent être redéfinies lorsque nécessaire Le concept de Sous-type est proche mais différent de celui de sous-classe et d'héritage. Il dépasse le cadre des langages objets ; il veut dire que les instances du sous-type sont systématiquement substituables aux instances du type. A la différence de l'héritage, il ne signifie pas que le sous-type est défini à partir du type en termes de sémantique et/ou d'implantation. Dans le cas de tableaux d'objets on préférera employer le vocabulaire type/sous-type dans la mesure où les tableaux en Java ne sont pas eux-mêmes des classes. 134

124 Compléments sur les classes Attention : redéfinition de la méthode equals() La méthode doit impérativement être réflexive, symétrique, transitive, consistante, et retourner false si une seule des références comparées vaut null. Suggestion : penser à utiliser instanceof() pour écrire equals(), exemple : class Cercle{ //... public boolean equals(object o){ if (o instanceof Cercle){ boolean x = centre.equals(o.centre); x = x && (rayon==o.rayon); return x; else { return false; Remarque : redéfinition de la méthode hashcode() En cas de redéfinition de la méthode equals(), il est vivement recommandé de redéfinir aussi la méthode hashcode(). Il est en effet essentiel que la méthode hashcode() retourne la même valeur pour toutes les instances considérées comme égales par la méthode equals() redéfinie. A défaut, certaines méthodes prédéfinies de Java produiront des résultats erronés (i.e. la méthode add() de la classe HashSet). Conseil Sous Eclipse, le plus efficace pour redéfinir les méthodes equals() et/ou hashcode() consiste à les générer à partir du menu «Source -> Generate hashcode() and equals()». D'une manière générale beaucoup de tâches plus ou moins complexes et/ou fastidieuses peuvent être effectuées efficacement à l'aide des menus «Source» et «Refactor» d'eclipse (génération d'un constructeur, création d'un bloc try/catch, etc.). L'équivalent existe sur NetBeans (alternative à Eclipse). Remarque : redéfinition de la méthode finalize() Il est possible de bloquer la destruction d'un objet via sa méthode finalize() en recréant une ou plusieurs références pointant sur l'objet. Dans tous les cas, la méthode finalize() n'est jamais invoquée plus d'une fois sur un même objet (y compris si de nouvelles références ont été crées sur l'objet lors d'un appel précédent à finalize(). 135

125 15. Méthode clone() La méthode clone() de la classe Object permet de dupliquer un tableau ou une instance (recopie des attributs) Sur les tableaux, clone() est directement utilisable : int[] tab = { 1, 2, 3, 4 ; int[] tab2 = tab.clone() ; ATTENTION : pour les tableaux multi-dimensionnels et pour les tableaux d'objets car la méthode clone() telle que définie dans la classe Object copie les références (et pas les objets référencés) Sur les objets, clone() n'est pas toujours utilisable par défaut les objets ne sont pas «clonables», pour pouvoir leur appliquer la méthode clone() il faut : 1. déclarer que la classe implante l'interface Cloneable 2. redéfinir la méthode clone() en tenant compte des spécificités de la classe (e.g. attributs de type référence) NOTA-BENE : certaines classes pré-définies en Java (mais pas toutes) implantent l'interface Cloneable (voir la documentation en-ligne des classes Java) ; pour les classes définies par l'utilisateur, c'est à lui de décider si il veut ou pas qu'elles soient clonables, et le cas échéant, si il convient ou pas de redéfinir la méthode clone() héritée. Conseil : rendre «clonable» une classe avec des attributs de type référence Si une classe Cls contient des attributs de type référence et qu'on veut la rendre «cloneable», le mieux à faire consiste à : 1. inclure dans Cls un constructeur par recopie : Cls(Cls x)){ redéfinir la méthode clone() de Cls en utilisant le constructeur par recopie : Object clone() { return (Object) new Cls(this); 3. déclarer que Cls implante l'interface Cloneable 16. Programmation «générique» via la classe Object La classe Object permet aussi de faire de la programmation générique, i.e. des classes ou fonctions qui peuvent fonctionner avec des instances de n'importe quelles classes Exemple de fonction générique : int chercher(object o, Object[] tab) { for (int i=0 ; i<tab.length ; i++) { if (o.equals(tab[i])) { return i; return -1; Exemple de fonction «générique» prédéfinie en Java : java.util.arrays.sort(object[] tab) 136

126 Compléments sur les classes NOTA-BENE : depuis Java 1.5, la programmation «générique» se fait plutôt sous forme paramétrée E. Introspection Chaque classe (et interface) est représentée par une instance de la classe Class (cf. La classe Class p 164) La classe Class permet d'instancier une classe à partir de son nom : Class cl; cl = Class.forName("NomPackage.NomDeClasse"); Object o = cl.newinstance(); Les classes Class, Method, Field et Constructor permettent d'explorer (et invoquer) dynamiquement du code Java (on parle alors d'introspection) : Method[] getdeclaredmethods() Field[] getdeclaredfields() Constructors[] getdeclaredconstructors() Class[] getinterfaces() Class getsuperclass() boolean isinterface() //... Complément On appelle «introspection» (en anglais : reflection), la possibilité dans un langage de programmation de pouvoir étudier dynamiquement le code en cours d'exécution, avec dans le cas d'un langage objet, la possibilité de naviguer dans le réseaux de classes/attributs/méthodes. Certains programmes sont de fait bien plus simples à écrire si on peut utiliser ce mécanisme. Exemple : supposons que pour tester une classe on souhaite disposer d'une interface homme-machine qui donne accès à la liste complète des méthodes définies dans cette classe ; en utilisant l'introspection pour construire la liste des fonctions de la classe on est certain que la liste sera toujours à jour sans pour autant avoir à la mettre à jour, d'où un gain de temps (et de fiabilité). En Java, l'introspection est possible à travers les méthodes de la classe Class, Field et Method. Elle inclut la possibilité d'instancier une classe et/ou d'invoquer une méthode dont le nom est déterminé à l'exécution du code. Toutefois, il n'est pas possible en Java d'utiliser la classe Class pour modifier une classe à l'exécution (i.e. ajouter ou supprimer un attribut ou une méthode par exemple). ATTENTION : l'introspection peut permettre de contourner le typage fort au niveau du compilateur Java mais ce faisant on prend le risque de générer des erreurs (IllegalArgumentException) lors de l'exécution du programme. Autrement dit, le typage fort en Java n'est pas juste lié aux vérifications effectuées par le compilateur (et qui se matérialisent par des interdits sous Eclipse), il est plus fondamentalement lié aux mécanismes de contrôle qu'applique systématiquement la machine virtuelle au bytecode lors de son exécution. On ne peut donc pas utiliser l'introspection pour contourner le typage de Java et programmer ainsi comme on le ferait dans un langage faiblement typé! 137

127 Conseil Penser au tutoriel d'oracle18 sur le sujet pour approfondir cet aspect du langage (le tutoriel d'oracle est organisé sous forme de sentiers dont un sentier intitulé «The Reflection API».)

128 XII - Interfaces XII Interfaces 139 Exemple d'interfaces 140 Autres exemples d'interfaces 140 Interfaces prédéfinies en Java 141 Héritage entre interfaces 141 Implantation d'une interface par une classe 141 Interface dans une déclaration d'attribut, variables, Interfaces en paramètres de méthodes 142 Interfaces «marqueurs» 142 Interfaces Serializable, Externalizable et mot-clé transient 143 Interfaces fonctionnelles 144 Passage d'une fonction/méthode en paramètre de méthode 144 Méthodes par défaut 146 Corps de méthodes statiques dans une interface 146 Comparaison interfaces / classes abstraites 147 A. Interfaces Interface = ensemble de signatures = ensemble de méthodes toutes abstraites Intérêt : équivaut à un «type abstrait de données» ; permet de spécifier des fonctionnalités indépendamment de leur implantation ; permet ensuite de vérifier/imposer la présence de ces fonctionnalités au niveau d'une classe ou d'une instance. NOTA-BENE : contrairement à une classe, une interface ne peut jamais être instanciée ; son rôle consiste à servir de modèle à des classes. Remarque En Java, une interface peut aussi contenir : des constantes de classe ; des méthodes «par défaut» (cf. Méthodes par défaut p 146) ; des méthodes statiques avec leur corps (cf. Corps de méthodes statiques dans une interface p 146). 139

129 Complément Les constantes définies dans une interface sont toujours public, static et final : ces mots-clés peuvent donc être omis, ils sont implicites dans le contexte d'une interface. De même, les méthodes définies dans une interface sont toujours abstraites et publiques (sauf cas particulier des méthodes «par défaut») : inutiles donc de les qualifier de public et abstract. B. Exemple d'interfaces Définition d'une interface, puis d'une classe qui «implante» cette interface : public interface Mesurable { public double calculersurface(); public double calculerperimetre(); // Toute classe «mesurable» devra obligatoirement // implanter ces deux méthodes // (sinon ce sera une classe abstraite). public class Cercle implements Mesurable { // public double calculersurface() { return ( PI*rayon*rayon ); public double calculerperimetre() { return( 2*PI*rayon ); // C. Autres exemples d'interfaces interface Redimensionnable { void grossir(int facteur); void reduire(int facteur); interface Coloriable { // NOTA-BENE : // possibilité de définir des constantes : Couleur ROUGE = new Couleur("rouge"); Couleur NOIR = new Couleur("noir"); //... void colorier(couleur c); interface Pile { void empiler(object o); void depiler(); boolean estvide(); //

130 Interfaces D. Interfaces prédéfinies en Java Il existe beaucoup d'interfaces prédéfinies en Java, parmi les plus importantes : cœur du langage : Appendable, Cloneable, Comparable, Iterable, Runnable... E/S : Serializable, Externalizable, Closeable,... collections : Collection, List, Queue, Set, Map, Comparator,... threads : Runnable,... IHMs (AWT) : LayoutManager, Ajustable, ImageProducer, ActionListener, KeyListener, Icon, ImageObserver, E. Héritage entre interfaces Une interface peut «dériver» (ou «hériter») d'autres interfaces : interface Externalizable extends Serializable { //... F. Implantation d'une interface par une classe Une interface peut être «implantée» par un nombre quelconque de classes. Une classe peut implanter zéro, une, ou plusieurs interfaces, exemple : class C implements Runnable, Cloneable { //... G. Interface dans une déclaration d'attribut, variables,... Lors d'une déclaration d'attributs ou de variable, il est possible d'indiquer une interface à la place du type : Coloriable fig; Cercle c = new Cercle(...); //... fig = c; // OK si Cercle implante Coloriable NOTA-BENE : une référence à une interface peut désigner toute instance de toute classe qui implante l'interface en question. Attention Les méthodes applicables dépendent de la nature de la référence : Cercle cercle = new Cercle(); Redimensionnable redim = cercle; Coloriable col = cercle; // cercle, col et redim sont trois // du même objet. vues différentes 141

131 // ATTENTION : dans un tel cas, les méthodes applicables // dépendent de la vue utilisée : col.colorier(coloriable.rouge); col.grossir(2); redim.grossir(2); cercle.colorier(coloriable.rouge); // // // // OK ERREUR OK OK H. Interfaces en paramètres de méthodes Dans une signature de méthode, il est également possible d'indiquer une interface à la place du type : void envoyer(serializable item) {... //... envoyer(c); // OK si Cercle implante Serializable RAPPEL : une référence à une interface peut désigner toute instance de toute classe qui implante l'interface en question. Autre exemple : interface Comparable { int compareto(object o); class Tri { public static void trier(comparable[] tab) { //... if (tab[i].compareto(tab[j]) > 0) { //... class W implements Comparable { //... public int compareto(object o) {... W[] tabw = new W[10]; //... Tri.trier(tabW); I. Interfaces «marqueurs» Définition On appelle interface «marqueur» ou «interface de marquage» (en anglais : marker interface) une interface qui ne contient aucune méthode ni constante, et sert juste à préciser une propriété des classes qui l'implantent. Exemples de telles interfaces pré-définies en Java : - interface Cloneable pour identifier les classes dont les instances peuvent être dupliquées par appel à la méthode clone() (cf. Méthode clone() p 136) - interface Serializable pour identifier les classes dont les instances peuvent être «sérialisées» (cf java.io) ; idem pour : Flushable, Closeable. 142

132 Interfaces J. Interfaces Serializable, Externalizable et mot-clé transient Complément Les méthodes readobject() et writeobject() (cf. En pratique : écriture d'un fichier «binaire» p 105) vues précédemment sont assez simples d'emploi tant qu'on se limite à leur fonctionnement par défaut. Etant donné leur grande utilité, il est toutefois souhaitable d'aller plus loin dans leur étude et réaliser que leur fonctionnement dans le cas général dépend de deux interfaces prédéfinies en Java : Serializable et Externalizable. En effet, selon qu'une classe «implante» ou pas ces interfaces, le fonctionnement des méthodes readobject() et writeobject() sera radicalement différent : Si la classe implante l'interface Externalizable alors : a. elle implante mécaniquement Serializable (car l'interface Externalizable hérite de Serializable) ; b. elle doit contenir deux méthodes : readexternal() et writeexternal() qui seront automatiquement invoquées, respectivement, en cas de readobject() et writeobject() ; c. ces méthodes doivent comporter l'intégralité du code nécessaire pour réaliser correctement ces opérations sur n'importe quelle instance de ces classes (y compris pour ce qui concerne l'ensemble des données des classes parentes) ; d. aucune autre méthode ne sera automatiquement invoquée. Si la classe implante Serializable sans implanter Externalizable alors : a. par défaut, readobject() et writeobject() liront/écriront l'ensemble des attributs de la classe et des classes parentes, à l'exception des attributs déclarées explicitement comme transient ; NOTA-BENE : dans une classe, le mot-clé transient sert à indiquer, le cas échéant, les attributs qui ne doivent pas être sauvegardés (ces attributs ne seront pas écrits avec le reste des attributs de la classe, et lors de la lecture ils seront initialisés à la valeur par défaut de leur type) ; b. il est possible en cas de besoins très particuliers de gérer à la main ces opérations en redéfinissant dans la classe les trois méthodes suivantes : void writeobject(java.io.objectoutputstream out) throws IOException void readobject(java.io.objectinputstream in) throws IOException, ClassNotFoundException void readobjectnodata() throws ObjectStreamException ATTENTION : ces méthodes doivent prendre en charger la sauvegarde et la relecture des attributs définis dans la classe mais pas ceux définis dans les classes parentes qui seront gérés automatiquement (de manière analogue, récursivement donc) ; c. lorsque l'on rend «serialisable» une classe dont la classe mère ne l'était pas, il est nécessaire que la classe mère comporte un constructeur par défaut (sans paramètre). [ lire la documentation de l'interface Serializable pour plus de détails. ] Si la classe n'implante ni Serializable ni Externalizable alors : a. les objets de cette classe ne peuvent pas être lus ou sauvegardés par les méthodes readobject() / writeobject() ; b. par défaut on est dans ce cas, mais il faut savoir que l'implantation d'une 143

133 interface est quelque chose qui s'hérite, autrement dit : une classe est «serializable» si elle est déclarée comme telle ou si l'une des classes dont elle hérite implante l'interface Serializable (idem pour Externalizable). K. Interfaces fonctionnelles Définition Interface contenant une et une seule méthode abstraite non-statique. Une interface fonctionnelle peut contenir un nombre quelconque de : méthodes non-statiques ; méthodes «par défaut» (cf. Méthodes par défaut p 146). Complément L'annotation (cf. Annotations p avant une définition d'interface permet de s'assurer que l'interface comporte bien une et une seule méthode abstraite non-statique (surtout elle empêche qu'un programmeur y ajoute involontairement une seconde méthode abstraite dans le futur et transforme ainsi une interface fonctionnelle en interface ordinaire). L. Passage d'une fonction/méthode en paramètre de méthode Jusqu'à la version 1.8 de Java (2014), le seul moyen de passer une fonction en paramètre à une méthode m() consistait à : 1. définir une interface I pour encapsuler la fonction à passer en paramètre ; 2. définir une classe Ck implantant I pour chaque fonction fk différente susceptible d'être passée en paramètre à m() ; 3. définir m() comme prenant en paramètre un objet de type I ; 4. lors de l'invocation de m(), passer comme paramètre effectif correspondant à I une instance de la classe Ck. Exemple : interface FonctionAUneVariable { double appliquer(double d); class Sin implements FonctionAUneVariable { public double appliquer(double d) { return Math.sin(d); class DoubleExp implements FonctionAUneVariable { public double appliquer(double d) { return Math.exp(Math.exp(d)); class CN { public static double integrer(fonctionaunevariable f, double deb, double fin, double pas) { double s=0.0, x=deb; long n = (long) ((fin-deb)/pas)+1; for (long k=0 ; k<n ; k++, x+=pas) { s += f.appliquer(x); 144

134 Interfaces return s*pas; //... double d1 = CN.integrer(new Sin(), 0, Math.PI, 0.001); double d2 = CN.integrer(new DoubleExp(), 0, 4, 0.01); // d1 vaut 2.0 et d2 vaut ,0 Remarque La même technique peut être utilisée pour le type de retour : le type de retour d'une méthode peut être une interface permettant indirectement de désigner une méthode ou fonction. A partir de la version 8 de Java, le même exemple peut se coder beaucoup plus simplement en combinant interfaces fonctionnelles, «lambda expressions» et l'opérateur :: interface FonctionAUneVariable { double appliquer(double d); class CN { public static double integrer(fonctionaunevariable f, double deb, double fin, double pas) { double s=0.0, x=deb; long n = (long) ((fin-deb)/pas)+1; for (long k=0 ; k<n ; k++, x+=pas) { s += f.appliquer(x); return s*pas; //... double d1 = CN.integrer(Math::sin, 0, Math.PI, 0.001); double d2 = CN.integrer((d) -> Math.exp(Math.exp(d)), 0, 4, 0.01); NOTA-BENE : la notation C::m permet de désigner directement la méthode m définie dans la classe C ; l'opérateur -> sert à définir une lambda expression (indispensable dans l'exemple ci-dessus vu que la fonction double-exponentielle n'est pas définie en tant que telle comme l'est la fonction sinus dans la paquetage Math). En utilisant l'interface fonctionnelle prédéfinie «Function» du package java.util.function, il est possible d'alléger encore le code (plus besoin de coder d'interface telle que FonctionAUneVariable lorsque quelque chose d'équivalent existe dans le package java.util.function) : import java.util.function.function; class CN { public static double integrer(function<double, Double> f, double deb, double fin, double pas) { double s=0.0, x=deb; long n = (long) ((fin-deb)/pas)+1; for (long k=0 ; k<n ; k++, x+=pas) { s += f.apply(x); return s*pas; 145

135 //... double d1 = CN.integrer(Math::sin, 0, Math.PI, 0.001); double d2 = CN.integrer((d) -> Math.exp(Math.exp(d)), 0, 4, 0.01); NOTA-BENE : l'interface fonctionnelle prédéfinie Function<T, V> comporte une méthode abstraite unique apply() prenant en paramètre une instance de la classe T et retournant une instance de la classe V ; en typant le premier paramètre de la méthode integrer() par Function<Double, Double> f, on indique que la méthode integrer() accepte comme premier paramètre toute fonction prenant en paramètre (et retournant) une instance de la classe Double (le type Double étant compatible avec le type primitif double, on peut comme dans l'exemple invoquer integrer() avec une fonction travaillant sur des double comme Math.sin()). Remarque Les lambda-expressions, les références sur méthodes/fonctions ainsi que le package java.util.function ne sont pas détaillés dans ce document. M. Méthodes par défaut Contexte : si on ajoute a posteriori une méthode m() à une interface I alors il faut ajouter cette nouvelle méthode dans toutes les classes qui implantent I. Problème : comment faire si I fait partie d'une bibliothèque de classes très répandue ; si I est implantée dans des milliers de programmes codés par des centaines de programmeurs? Solution : utiliser le mot clé default pour assortir chaque nouvelle méthode d'une implantation par défaut (éventuellement vide). Effet obtenu : les classes qui implantent I sans implanter m() héritent de l'implantation par défaut (donc pas besoin de toutes les modifier). Attention Les méthodes par défaut ne peuvent pas utiliser les variables d'instance de la classe. Si dans deux interfaces il existe une méthode par défaut commune (avec la même signature) alors tout classe qui implante ces deux interfaces devra impérativement surcharger cette méthode (erreur de compilation sinon). Soit une classe C qui implante une interface I où est définie une méthode par défaut m(), alors si m() est surchargée dans C, son implantation par défaut dans I reste accessible depuis la classe C avec la syntaxe : I.super.m(); N. Corps de méthodes statiques dans une interface Il est possible de définir des méthodes statiques dans une interface dont le code sera partagé par toutes les classes qui implantent cette interface. Mise en œuvre : utiliser le mot clé static et définir le corps de la méthode. Intérêt : proposer des méthodes utilitaires destinées à faciliter la programmation des classes implantant cette interface. 146

136 Interfaces O. Comparaison interfaces / classes abstraites Beaucoup de points communs : non-instanciables ; contiennent des définitions de méthodes avec ou sans leur implantation. Principales différences «techniques» : possibilité de définir des attributs non-statiques dans les classes abstraites ; les mots-clés liés à la visibilité (public/private/...) sont sans effet dans les interfaces ; une classe peut «implanter» un nombre quelconque d'interfaces ; elle ne peut «hériter» que d'une seule classe (abstraite ou pas). En termes d'usage : les classes abstraites servent à définir un début d'implantation (modèle de ses classes filles, définition des éléments communs) ; les interfaces servent à caractériser, spécifier formellement quelque chose (un type, une propriété,...) Conseil : lorsque les deux sont techniquement possibles, comment choisir entre définir une interface et une classe abstraite? Il vaut mieux définir une classe abstraite : lorsqu'elle représente clairement un sur-ensemble de ses classes filles, et de ses classes filles uniquement ; lorsque cette caractérisation de la relation classes mère abstraite / classes filles est à la fois intangible et essentielle (exemple : FigureGeometrique en tant que classe mère abstraite de Rectangle, Cercle,...) ; lorsque vous pourriez ultérieurement avoir besoin d'y définir des attributs nonstatiques ou d'y qualifier certains éléments de public/private/... Inversement, une interface est préférable : si les classes ayant vocation à implanter cette interface sont de nature très différentes (exemple : les interfaces Cloneable, Comparable,...) ; si il s'agit de spécifier un comportement (liste de méthodes) sans aucun début d'implantation (ni constructeur, ni attribut, ni corps de méthode). 147

137 Collections (listes, ensembles, files, tables) XIII - XIII Introduction 149 Deux versions : «paramétrée» ou pas 150 Les classes Collections et Arrays 151 Fiches pratiques et exemple d'utilisation 151 Principales interfaces et classes 154 A. Introduction Collection = structure de donnée permettant de rassembler plusieurs éléments (ex. : tableau, liste, ) Java propose dans le paquetage java.util plusieurs sortes de collections : les listes : collection forcément ordonnée, avec possibilité de répétition du même élément les ensembles (plusieurs variantes) : aucun élément dupliqué les files (plusieurs variantes) : correspond au type abstrait «file» les tables d'association (plusieurs variantes) : série de couples [clef valeur ] Les principales collections de java.util 149

138 Complément Le paquetage java.util s'enrichit régulièrement, au fil des nouvelles versions du langage Java 1.8 propose ainsi 9 sortes de collections (interfaces correspondant à un type abstrait) et plus de 20 implantations (classes). D'autres paquetages proposent d'autres sortes de collections (java.util.concurrent, en particulier, propose des collections fort utiles dans un contexte multi-threadé). Remarque A chaque sorte de collection correspond : une interface (spécification du type abstrait en question) une ou plusieurs classes qui implantent cette interface (avec des stratégies différentes en termes de stockage en mémoire et/ou d'algorithmes). Attention Plusieurs restrictions à connaître lorsqu'on utilise les collections de Java : Les collections ne peuvent contenir que des objets (pas de types primitifs) Les types ArrayList, ArrayList<String> et ArrayList<Integer> (par exemple) sont distincts et incompatibles (bien qu'il n'y ait en fait qu'une unique classe ArrayList) Il est impossible de créer des tableaux dont les éléments sont d'un type paramétré (new ArrayList<String>[3] est par exemple illégal!) utiliser à la place des collections de collections, e.g. : ArrayList<ArrayList<String>> lili ; lili = new ArrayList<ArrayList<String>>() ; B. Deux versions : «paramétrée» ou pas Il existe deux versions de chaque interface et classe : 1. version «paramétrée» par le type des éléments : stocke des éléments de n'importe quelle classe (pas de types élémentaires) interdit de mélanger des éléments de nature différente (typage fort) aucune opération particulière à coder lors des sorties de la collection version à privilégier sauf cas très particuliers (e.g. contenu hétérogène) 2. version «non paramétrée» : stocke des éléments de la classe Object (converstion automatique vers Object à l'entrée dans la collection => aucun contrôle du typage en entrée) permet de mélanger des éléments de nature différente nécessite de convertir depuis la classe Object vers la classe véritable lors des sorties de la collection 150

139 Collections (listes, ensembles, files, tables) C. Les classes Collections et Arrays La classe Collections collections : trier : sort() contient de nombreuses fonctions utilitaires sur rechercher le plus petit/grand élément : min() et max() remplir toutes les cases avec un même élément : fill() réarranger aléatoirement : shuffle() tester la présence d'éléments communs dans deux collections : disjoint() compter le nb. d'occurences d'un élément : frequency() les NOTA-BENE : la classe Arrays contient le même genre de fonctions pour les tableaux. D. Fiches pratiques et exemple d'utilisation 1. Utilisation d'une liste import java.util.*; class Individu { //... Création d'une liste d'individus : LinkedList <Individu> rep = new LinkedList <Individu>(); Ajout d'un individu rep.addfirst(x); rep.addlast(x); rep.add(i, x); Retrait d'un individu de la liste : rep.removefirst(); // retire le rep.removelast(); // retire le rep.remove(i); // retire le rep.remove(x); // retire la xà // // // la liste ajoute ajoute ajoute : en première position en dernière position en i-ème position 1er élément dernier élément i-ème élément 1ère occurrence de l'objet x Accès à un individu de la liste : x = rep.get(i); // pour récupérer le ième de la liste 2. Parcours avec un Iterator Création d'un itérateur qui pointe AVANT la position 0 : ListIterator <Individu> iter = rep.listiterator(0); Existence d'un élément suivant / précédent : boolean ok = iter.hasnext(); // renvoie true ou false boolean ok = iter.hasprevious(); // renvoie true ou false Renvoyer l'élément suivant / précédent : Individu x = iter.next(); Individu x = iter.previous(); Renvoyer l'indice de l'élément suivant/précédent : int i = iter.nextindex(); int i = iter.previousindex(); 151

140 3. Exemple d'utilisation de la classe LinkedList On crée une liste de String (de type LinkedList) sur laquelle on exécute quelques méthodes de l'interface List : import java.util.*; public class ExempleList { public static void main(string[] args) { List<String> pn; // DECLARATION D'UNE LISTE pn = new LinkedList<String>(); // CHOIX DE L'IMPLANTATION pn.add("paul"); pn.add(0, "Léa"); pn.add("julie"); // INSERTION // INSERTION (EN *DEBUT* DE LISTE) // INSERTION (EN FIN DE LISTE) System.out.println(pn); // AFFICHAGE int n = pn.size(); // ACCES A LA TAILLE System.out.println("Nombre d'elements = " + n); pn.set(1, "Marc"); // REMPLACEMENT D'UN ELEMENT // ACCES A UN DES ELEMENTS DE LA LISTE : String nom = pn.get(1); // ->"Marc" System.out.println(nom); // SUPPRESSION D'UN ELEMENT : pn.remove(1); // retire "Marc" //... On utilise un itérateur pour parcourir pn : // PARCOURS DE LA LISTE AVEC UN ITERATEUR : ListIterator<String> iter = pn.listiterator(); while (iter.hasnext()) { // tant qu'il reste un élément, accès à l'élément suivant : String s = iter.next(); System.out.println(s); if (s.equals("léa")) { iter.add("jean"); // modification via l'itérateur String s = iter.previous(); // retour en arrière iter.remove(); // modification via l'itérateur pn.add("alain"); // modification sans passer par l'iterateur! System.out.println(pn); // OK // ATTENTION : l'itérateur n'est plus valide après // modification de la liste originale : System.out.println(iter.next()); // INTERDIT! // -> ConcurrentModificationException 152

141 Collections (listes, ensembles, files, tables) 4. Définition d'une relation d'ordre / l'interface Comparable L'interface Comparable<E> spécifie que toute instance de la classe qui l'implante peut être comparée à toute instance de la classe E. Elle contient une seule méthode : public int compareto(e autre); qui doit retourner une valeur : < 0 ssi this «est avant» autre, > 0 ssi this «est après» autre, = 0 ssi les deux objets sont «égaux» Elle permet d'utiliser les fonctions pré-programmées telles que sort(), exemple : Class C implements Comparable <C> { //... public int compareto(c autre) {... Utilisation avec une liste l d'instances de la classe C : Collections.sort(l); Idem avec un tableau : Arrays.sort(tab); 5. Définition d'ordres multiples / l'interface Comparator L'interface Comparator<E> permet de définir plusieurs relations d'ordre (via plusieurs implantions) ; elle nécessite de définir une méthode de signature : public int compare(e e1, E e2); qui doit retourner une valeur : < 0 ssi e1 «est avant» e2, > 0 ssi e1 «est après» e2, = 0 ssi les deux objets sont «égaux» Elle permet d'utiliser les fonctions pré-programmées telles que sort() pour réaliser des tris multi-critères, exemple : class ComparePrix implements Comparator <Produit> { public int compare (Produit o1, Produit o2) { return (int) (o1.getprix () - o2.getprix () ) class CompareNom implements Comparator <Produit> { public int compare (Produit o1, Produit o2) { return o1.getnom.compareto( o2.getnom () ); Utilisation avec une liste : Collections.sort(listeProduits, new ComparePrix()); Collections.sort(listeProduits, new CompareNom()); Idem avec un tableau : Arrays.sort(tabProduits, new ComparePrix()); Arrays.sort(tabProduits, new CompareNom()); 153

142 E. Principales interfaces et classes 1. L'interface Collection L' interface Collection (ou plutôt l'interface Collection<E>, où E est le type des éléments) regroupe les méthodes communes à toutes les collections : taille : int size() test si vide : boolean isempty() ajout : boolean add(e elt) suppression : boolean remove(e elt) suppression de tous les éléments : void clear() recherche : boolean contains(e elt) création d'un itérateur : Iterator<E> iterator() conversion en tableau : Object[] toarray()... Remarque add(elt) renvoie false uniquement dans le cas où elt figure déjà dans la collection et que celle-ci interdit les duplicata. La présence de méthodes add(), clear() et remove() véritablement utilisables n'est pas garantie pour toutes les implantations qui implantent cette interface : certaines implantations peuvent en effet lancer l'exception UnsupportedOperationException quand on les appelle (cf. documentation des différentes implantations). 2. L'interface Iterator L'interface Iterator permet de parcourir n'importe quelle sorte de collection. Un itérateur : s'obtient par appel de iterator() sur la collection à parcourir contient les méthodes : boolean hasnext() E next() void remove() Attention Il faut impérativement re-créer nouveau itérateur (par appel de iterator()) dès que la collection originale a été modifiée [ par appel à add(), remove(),... en dehors de l'itérateur ] 3. Les listes / interface List L'interface List dérive de Collection, avec en plus des méthodes pour l'accès par position, et itérateur spécifique : E get(int index) E set(int index, E elt) void add(int index, E elt) 154

143 Collections (listes, ensembles, files, tables) E remove(int index) int indexof(e elt) ListIterator<E> listiterator(int debut) ListIterator<E> listiterator()... Trois implantations : classe LinkedList<E> (liste doublement chaînée) classe ArrayList<E> (tableau) classe Vector<E> (implantation similaire à ArrayList mais «synchronized» + méthodes additionnelles) Complément : principales différences entre les classes ArrayList et Vector Vector est «synchronized» (utile en cas multithreading (cf. Programmation multi-threadée p 207)) alors que ArrayList ne doit pas être utilisé sans précaution depuis plusieurs threads Vector propose quelques méthodes additionnelles (voir documentation), dont : containesall(), copyinto(),... Vector pemet au programmeur de spécifier de combien la taille effective du tableau augmente lorsque sa capacité maximale est atteinte Historiquement, Vector est une classe ancienne qui existait avant l'introduction des Collections dans Java 1.2 En pratique, et dans le cas d'un usage dans un seul thread, la classe ArrayList est plus efficace (parcours, recherche,...) et la classe Vector plus puissante ; il est donc recommandé d'utiliser la classe ArrayList dès lors qu'on n'a pas besoin de ce qu'ajoute la classe Vector. 4. L'interface ListIterator L'interface ListIterator<E> est spécifiquement conçu pour parcourir les listes : s'obtient par appel de listiterator() sur la liste à parcourir étend l'interface Iterator<E> en ajoutant des méthodes : pour parcourir en sens inverse : previous(), hasprevious(),... pour insérer : add(e elt) pour modifier : set(e elt) ATTENTION : même restriction qu'avec les Iterator en cas de modification de la liste originale en dehors de l'itérateur. 5. Les piles / classe Stack La classe Stack dérive de la classe Vector, en ajoutant les méthodes : empiler : push(e item) sommet : E peek() dépiler : E pop() 155

144 Remarque En héritant de la classe Vector, la classe Stack de Java fournit une implantation du type abstrait pile qui inclut des méthodes permettant d'accéder directement à n'importe quel élément, et pas juste au sommet comme on pourrait s'y attendre pour une pile. 6. Les ensembles / interfaces Set et SortedSet Principale différence avec les listes : dans un ensemble, il est interdit de mettre deux fois le même élément. L'interface Set<E> contient les mêmes méthodes que Collection<E>, plus les méthodes suivantes : Test d'inclusion : e1.containsall(e2) Union : e1.addall(e2) [modifie e1!] Intersection : e1.retainall(e2) [modifie e1!] L'interface SortedSet<E> y ajoute des méthodes pour : accéder au plus grand ou au plus petit : last(), first() extraire un sous-ensemble : subset(e min, E max),... Deux implantations : classe HashSet<E> pour Set<E> (utilisant une table de hachage HashMap<E, Object>) classe TreeSet<E> pour SortedSet<E> (utilisant un «arbre bicolore» TreeMap<E, Object>) 7. Les files d'attente / interface Queue L'interface Queue<E> offre les fonctionnalités d'une file d'attente. En plus des méthodes de Collection, on trouve : essai d'ajout : boolean offer(e elt) : [idem add(elt), sauf que la réussite de l'ajout dans la file n'est pas garanti (cas d'une file pleine...)] récupération et suppression de l'élément en tête (si file non vide) : E poll() E remove() : idem poll(), mais lance NoSuchElementException si la file est vide accès à la tête de file : E peek() E element() : idem peek() mais lance NoSuchElementException si la file est vide NOTA-BENE : il existe une variante BlockingQueue<E> qui, en cas d'essai d'accès à la tête, bloque jusqu'à ce que la file soit non-vide. 156

145 Collections (listes, ensembles, files, tables) 8. Implantations de l'interface Queue La principale implantation de l'interface Queue est la classe PriorityQueue<E> (éléments traités selon leur ordre «naturel») Autres implantations, dans le paquetage java.util.concurrent : LinkedBlockingQueue<E> : une FIFO («First In First Out») bloquante. ArrayBlockingQueue<E> : une FIFO («First In First Out») bloquante à capacité limitée (stockage dans un tableau). PriorityBlockingQueue<E> : idem PriorityQueue<E> mais en version bloquante DelayQueue<E> : les éléments doivent implanter l'interface Delayed, et ne sont traités qu'une fois leur «délai» expiré, en commençant par ceux ayant expiré les premiers 9. Les tables d'association / interface Map Une table d'association = série de couples (clef valeur) telle que : 1. toute clef est présente au plus une fois dans la table 2. chaque clef est associée à une unique valeur Principales méthodes de l'interface Map<K,V> [ paramétrée par les types respectifs K et V des clefs et des valeurs] : ajout d'un couple : put(k clef, V valeur) valeur associée à une clef : V get(object clef) suppression : V remove(object clef) taille : boolean isempty() et int size() recherche par clef : boolean containskey(object clef) recherche par valeur : boolean containsvalue(object val) collection des valeurs : Collection<V> values() ensemble des clefs : Set<K> keyset() ensemble des couples clef-valeur : Set<Map.Entry<K,V>> entryset() [ chaque couple est une instance de Map.Entry<K,V> ] 10. Table d'association triée / interface SortedMap SortedMap<K,V> est un cas particulier de Map<K,V> qui garantit que les couples sont stockés par ordre croissant de clef Méthodes supplémentaires par rapport à Map : K firstkey() K lastkey() SortedMap headmap(k cleflimite) SortedMap tailmap(k cleflimite) SortedMap submap(k clefmin, K clefmax) 157

146 11. Principales implantations de l'interface Map Deux implantations principales : HashMap<K,V> = implantation de Map<K,V> par hachage TreeMap<K,V> = implantation de SortedMap<K,V> par «arbre bicolore» Il existe une autre implantation de Map, très voisine de HashMap : la classe Hashtable. En plus des méthodes standards de Map, elle possède les méthodes suivantes : liste des éléments : Enumeration elements() liste des clef : Enumeration keys() 12. Collections et enum La classe EnumSet<E extends Enum<E>> est une implantation de Set spécialisée (et optimisée) pour le stockage de valeurs d'un même type énuméré (enum) : pas de constructeur : la création se fait par une des méthodes «static» de la classe ; exemple : Set<MonEnum> s; s = EnumSet.allOf(MonEnum.class); Manipulation avec les méthodes standard d'un Set Complément EnumMap<K extends Enum<K>, V> est une classe offrant une implantation de Map spécialisée et optimisée pour des tables d'association dont les clefs sont des valeurs d'un même type énuméré. 158

147 Le paquetage java.lang XIV - XIV Le paquetage java.lang 159 La classe Math 160 La classe StrictMath 161 La classe System 161 La classe Runtime 162 La classe Process 162 Les classes «enveloppes» 162 La classe Character 163 La classe Number et ses classes filles 163 La classe Enum 164 La classe Class 164 La classe Field 165 La classe Method 166 Interfaces pré-définies à connaître 166 A. Le paquetage java.lang Contient une trentaine de classes parmi les plus importantes de Java : la classe «racine» : Object (cf. la classe «Object» p 134) les classes : String, StringBuffer, StringBuilder (cf. Chaînes de caractères p 53) des classes essentielles : Math, System, Runtime, ClassLoader, Thread,... huit classes «enveloppes» permettant d'encapsuler les huit types élémentaires dans des objets : Boolean, Character, Integer, Long, Short, Byte, Double, Float la classe abstraite Number (classe mère d'integer, Double, Float,...) la classe abstraite Enum (classe mère des types énumérés) des classes permettant «l'introspection» : Class, Method, Field, Contient aussi quelques interfaces importantes : Comparable, Runnable,... NOTA-BENE : ce paquetage est importé automatiquement. 159

148 B. La classe Math Constantes : Math.PI, Math.E Calcul entre flottants (type double en entrée et en sortie) : sin(), cos(), tan(), acos(),... todegrees(), toradians() sqrt(), exp(), log(), log10(), pow(),... nextup(), nextdown(), ceil(), floor(), rint(), Calcul entre entiers (type int ou long) avec lancement d'une exception en cas de dépassement : addexact(), subtractexact(), multiplyexact(),... tointexact() Autres fonctions : int round(float), long round(double) : arrondis à l'entier le plus proche float signum(float), double signum(double) : selon le signe, retourne -1.0, 0.0 ou 1.0 abs(a), min(a,b), max(a,b) pour a et b : int, long, float ou double double random() : nombre compris dans l'intervalle [ [ et tiré, par défaut, d'une série pseudo-aléatoire nouvelle à chaque exécution du programme19 NOTA-BENE : toutes les méthodes de la classe Math sont statiques (elles s'invoquent en les préfixant par le nom de la classe : Math.sin(x), Math.sqrt(y),...) Complément : Arrondis Plusieurs fonctions permettent d'arrondir une valeur flottante : ceil(x) : arrondi à l'entier supérieur ou égal (sous forme de double) floor(x) : arrondi à l'entier inférieur ou égal (sous forme de double) rint(x) : arrondi à l'entier le plus proche (sous forme de double) round(x) : arrondi à l'entier le plus proche (sous forme d'entier) (int) x : conversion explicite en entier (consiste à supprimer tout ce qui suit la virgule) EXEMPLE : double x = -5.75; double a = Math.ceil(x); double b = Math.floor(x); double c = Math.rint(x); int m = Math.round(x); int n = (int) x; // // // // // a b c m n vaut vaut vaut vaut vaut Remarque Ne pas confondre la classe Math (du paquetage java.lang) et le paquetage java.math (cf. La classe Number et ses classes filles p 163). Les fonctions dans la classe Math utilisent autant que possible les routines 19 - Pour la génération de nombres pseudo-aléatoires, voir aussi la classe java.util.random. 160

149 Le paquetage java.lang optimisées disponibles au niveau de l'environnement matériel (e.g. processeur) ; elles peuvent donc produire des résultats différents selon les machines (voir ci-après). C. La classe StrictMath StrictMath est identique à la classe Math en termes de fonctionnalités, mais avec des caractéristiques différentes en termes de performances et de portabilité : utilise des algorithmes standards définis dans la bibliothèque mathématique fdlibm «Freely Distributable Math Library» résultats des calculs strictement identiques quelque soit le matériel utilisé performances possiblement inférieures comparées à celles de la classe Math (lorsque le hardware utilisé fournit des routines optimisées). Conseil Si la vitesse est primordiale utiliser la classe Math Si la portabilité des résultats des calculs est essentielle StrictMath. utiliser la classe Remarque Selon les machines il est tout à fait possible qu'une partie (voire la totalité) des méthodes des classes Math et StrictMath retournent exactement les mêmes résultats. Complément : le mot-clé strictfp Dans la même veine que la classe StrictMath, le mot clé strictfp (pour Strict Floating Point) sert à indiquer que les calculs en virgules flottantes doivent se faire dans le strict respect des spécifications Java, même si cela engendre une dégradation de performance. Il peut être utilisé lors de la définition d'une méthode, d'une classe ou d'une interface. Par défaut (en omettant le mot-clé strictfp ) les machines virtuelles Java sont autorisées à optimiser certains calculs et/ou à tirer profit de telle ou telle possibilité du matériel (processeur), ce qui peut conduire à des différences dans les résultats de calculs en virgules flottantes entre deux exécutions d'un même programme sur des machines différentes. D. La classe System La classe System contient beaucoup de choses très utiles : lancement forcé du Garbage Collector : System.gc() ordre de fin d'exécution : System.exit(int status) accès aux variables d'environnement : String System.getProperty(Sring name)... copie rapide de tableau : System.arraycopy(src, deb, dest, debd, len) entrée-sorties standards : InputStream System.in, PrintStream System.out et System.err redirection des I/O : System.setIn(InputStream),... réglage sécurité : System.setSecurityManager(SecurityManager) heure (en ms depuis 1/1/1970) : long System.currentTimeMillis() 161

150 E. La classe Runtime La classe Runtime est instanciée une fois (et une seule) dans chaque programme Java s'exécutant. Principales méthodes : récupération d'une instance correspondant au programme courant : Runtime.getRuntime() lancement de programme externe (dans un process séparé) : Process exec(string commande) exemple : Runtime.getRuntime().exec("ls -l *.c"); bilan sur l'utilisation de la mémoire : long freememory() et totalmemory() F. La classe Process La classe abstraite Process permet de gérer les programmes externes lancés en tant que processus séparés vua la méthode exec() (cd. classe Runtime) : attente de fin et récupération du status : int waitfor() suppression du process : destroy() connexion avec les I/O standard : - InputStream getinputstream() : récupère la sortie standard (pour lire dessus) - OutputStream getoutputstream() : permet de se connecter à l'entrée standard du process (pour écrire des choses dessus) G. Les classes «enveloppes» Pour chacun des 8 types élémentaires (boolean, char, int,...), il existe une classe «enveloppe» (ou «wrapper») correspondante (Boolean, Character, Integer,...) pour pouvoir manipuler si nécessaire des valeurs élémentaires comme des objets. Elles ont toutes : un constructeur à partir d'une valeur du type primitif correspondant ; un constructeur à partir de String, et une méthode statique équivalente NomClasse.valueOf(String) ; une méthode tostring() ; un attribut TYPE avec l'objet de type Class correspondant. Remarque Les conversions dans les deux sens entre chaque type primitif et sa classe «enveloppe» se font automatiquement : Integer objentier = 4; // OK : équivalent de = new Integer(4); Double objdouble = Double.valueOf("1.618"); double x = 10.*objDouble; // OK : équivalent de = 10.*objDouble.doubleValue(); Object[] tab[0] = tab[1] = tab[2] = 162 tab = new Object[3]; true; 'W'; 33;

151 Le paquetage java.lang // OK : équivalent de tab[0]= new Boolean(true); // tab[1]= new Character('W'); // tab[2]= new Integer(33); H. La classe Character Character est la classe «enveloppe» du type primitif char : ne contient quasiment que des fonctions (méthodes statiques) test de la nature d'un caractère : - boolean Character.isLetter(char), - Character.isDigit(char), - Character.isWhiteSpace(char), -... Accès au type précis d'un caractère : - int Character.getType(char ch) renvoie un identifiant parmi Character.LOWERCASE_LETTER, Character.DECIMAL_DIGIT_NUMBER,... changement de casse : - char Character.toLowerCase(char), : I. La classe Number et ses classes filles Classe abstraite Number = classe mère des classes Byte, Integer, Double,... Contenu communs aux classes «enveloppes» numériques : valeurs min/max du type : constantes de classe MIN_VALUE et MAX_VALUE méthodes de conversion : byte floatvalue(),... bytevalue(), int intvalue(), float Classes Integer, Byte, Short, Long : très similaires évaluer un entier écrit sous forme de chaîne de caractères : int Integer.parseInt(String), byte Byte.parseByte(String),... idem en précisant une base : int Integer.parseInt(String s, int base) écriture en base 2 à 36 : String Integer.toString(int val, int base)... Classes Double et Float : très similaires évaluer un entier écrit sous forme de chaîne de caractères : double Double.parseDouble(String),... infinis : float Double.POSITIVE_INFINITY, float Double.NEGATIVE_INFINITY, boolean Double.isInfinite(double) valeur indéterminée : boolean Double.isNaN(double)

152 Complément : le paquetage java.math Deux classes du paquetage java.math héritent également de la classe Number : BigInteger : entiers en précision arbitraire, nombreuses fonctions disponibles dont certaines particulièrement pertinentes en cryptographie : isprobableprime(), modinverse(),... BigDecimal : chiffres décimaux de très grande précision, gestion fine des arrondis, possibilité de contrôler la précision des calculs20. NOTA-BENE : comme pour la classe String, les instances de ces deux classes sont immuables (une fois crée un objet de type BigInteger ne peut pas être modifié). Outre ces deux classes, java.math inclut MathContext pour spécifier la précision des calculs et les modalités d'arrondis dans le contexte de la classe BigDecimal. ATTENTION : le gain en précision et en possibilité de contrôle se paie cher en termes de performance (les temps de calculs avec des BigDecimal sont ainsi ±100 à 1000 fois plus lents qu'avec des double selon la précision demandée) et aussi de lisibilité du code. J. La classe Enum Enum est la classe abstraite ancêtre de tous les types énumérés (i.e. définis avec le mot-clef enum). Enum implante l'interface de comparaison Comparable de sorte que toute valeur d'un type énuméré est automatiquement comparable à toute autre valeur d'un même type énuméré ; l'ordre «naturel» utilisé par la méthode compareto(enum autre) est l'ordre de déclaration des constantes dans le type énuméré. K. La classe Class La classe «Class» contient la représentation abstraite des classes, interfaces et tableaux : obtention d'une instance de la classe Class : - via une instance : o.getclass() - ou par le nom : Class.forName("NomCompletClasse") littéraux : NomClasse.class (ex: String.class désigne la classe String) instanciation : Object newinstance() exploration des membres de la classe : - Method[] getdeclaredmethods() - Field[] getdeclaredfields() 20 - Contrôler finement la précision des calculs et des arrondis et particulièrement utile en finance lorsqu'il s'agit de manipuler des valeurs monétaires ; on pourra donc utiliser des instance de BigDecimal plutôt que des long pour représenter des montants exprimées dans une devise donnée (les types float et double sont à proscrire car le manque de précision des calculs rend très difficile l'obtention de résultats systématiquement juste au centime près ce qui est bien sur essentiel dans un contexte bancaire ou autre). 164

153 Le paquetage java.lang - Constructor[] getdeclaredconstructors() - Class[] getinterfaces() - Class getsuperclass() -... recherche d'un membre donné par son nom : Method getmethod(string), Field getfield(string),... informations sur la classe : - nom complet : String getname() - tostring() : idem, précédé de «class» ou «interface» selon les cas - boolean isinterface() - boolean isarray() - boolean isprimitive() - int getmodifiers() : retourne Modifier.PUBLIC Modifier.STATIC... un «masque» de la forme - type des éléments (pour tableaux seulement) : Class getcomponenttype() test d'appartenance d'un objet à la classe (instanceof dynamique) : boolean isinstance(object) accès aux annotations éventuelles (cf. Annotations p 177) : - Annotation[] getannotations() Définition : métaclasse En termes de langages objets, on appelle couramment «métaclasse» une classe permettant de représenter le concept de classe au sein du langage. Tous les langages objets ne comporte pas cette notion, et quand elle existe, elle peut s'incarner de différentes manières offrant plus ou moins de possibilités au programmeur. L'un des intérêts des métaclasses est de permettre l'introspection (cf. Introspection p 137). L. La classe Field La classe Field contient la représentation abstraite des attributs : implante l'interface Member : - String getname() - int getmodifiers() - Class getdeclaringclass() autres méthodes : - set(object instance, Object valeur) - void Object get(object instance) - Class gettype() (renvoie instances spéciales int.class, double.class, boolean.class,... si type primitif) - Annotation[] getannotations() 165

154 M. La classe Method La classe Method contient la représentation abstraite des attributs : implante l'interface Member Field (cf. La classe Field p 165) autres méthodes : - Class[] getparametertype() - Class getreturntype() - Object invoke(object instance, Object[] args) - Annotation[] getannotations() N. Interfaces pré-définies à connaître Le paquetage Java.lang définit une dizaine d'interfaces dont : CharSequence : implantée par les classes qui représentent une séquence de caractères (String, StringBuffer, StringBuildr, CharBuffer,...) Appendable : implantée par les classes permettant l'opération ajout de caractères (StringBuffer, FileWriter, PrintWriter,...) Cloneable : voir description de méthode clone() dans section classes/objets Comparable : interface de comparaison (voir section sur java.util) sur Iterable<T> : interface déclarant l'unique méthode Iterator<T> iterator(), et caractérisant les types permettant les «itérations simplifiées»21 Readable : source de caractères (implantée notamment par FileReader, StringReader,...) Runnable : voir section sur les thread C'est-à-dire les instruction de type for (item : séquence) {... (cf. Boucles d'itération «simplifiées» p 40). 166

155 Autres classes et interfaces à connaître XV - XV Le paquetage java.util 167 Les classes Scanner et Pattern 168 La classe Random 170 La classe Objects 171 Localisation et internationalisation 172 A. Le paquetage java.util Le paquetage java.util contient beaucoup de classes relativement importantes : classes et interfaces liées aux «collections» (cf. Introduction p 149) interface Formattable, classes Formatter,.. (cf. Entrées-sorties p 42) classes Scanner classe Random classe Objects classes Locale, ResourceBundle,... classe Currency classes Calendar, Date, Timer, TimeZone,... interface Observable et classe Observer... Remarque Depuis la version 1.8 de Java 1.8, le paquetage java.time fournit un ensemble de classes à la fois pratique et très complet pour gérer tous les aspects liés au temps (instants, durées, temps universel, temps local, calendriers alternatifs, etc.) Ces classes ne sont pas détaillées dans ce document ; si besoin penser à consulter le tutoriel d'oracle22 qui comporte un sentier intitulé «Date-Time APIs»

156 B. Les classes Scanner et Pattern La classe Scanner permet de «parser» (en français : décortiquer ou «analyser syntaxiquement») tout ce qui est «Readable23» (flux, Strings, etc.) : import java.util.scanner; //... String tst = "bleu 12 rouge 1,618"; Scanner sc = new Scanner(tst); String s = sc.next(); // s vaut "bleu" int k = sc.nextint(); // k vaut 12 double x = sc.nextdouble(); // InputMismatchException! //... Scanner sc2 = new Scanner(System.in); if (sc2.hasnextdouble()) { double y = sc2.nextdouble(); //... La classe Pattern du paquetage java.util.regex permet de définir et rechercher des «expressions régulières» : if ( Pattern.matches("[a-d].*[0-9]", chaine) ) {... Pattern pat = Pattern.compile("[^aeiouy]*\s"); Usage conjoint avec Scanner : if (scflux.hasnext(pat)){... Complément : expressions régulières On appelle expression régulière (ou expression rationnelle24 ou motif ou pattern) une chaîne de caractères qui utilise une syntaxe précise, typiquement à base de quelques caractères spéciaux habituellement :.? + * [ ] ( ) ^ et \ pour décrire un ensemble de chaînes de caractères possibles. Exemples : 7.[xy] représente l'ensemble des chaînes composées de trois caractères, commençant par le chiffre 7 et finissant par une lettre x ou y ; [a-za-z]* représente l'ensemble des chaînes composées exclusivement de lettres (minuscules ou majuscules de l'alphabet latin). On utilise très fréquemment des expressions régulières en informatique pour filtrer des données textuelles (par exemple dans une messagerie pour identifier des spams, ou dans un langage de script tel que PERL). Toutefois, selon les langages et outils informatiques, il existe des différences de syntaxe notamment concernant la sophistication des notations disponibles et l'usage 23 - L'interface java.lang.readable sert à identifier les classes pouvant servir de sources de caractères. Elle est implantée par une dizaine de classes prédéfinies de Java dont BufferedReader, CharArrayReader, FileReader, InputStreamReader, StringReader, La dénomination d'expression rationnelle fait référence aux «langages rationnels» (ou langages de type 3) qui regroupent l'ensemble des langages formels analysables par un automate fini. Il suffit donc d'un tel automate pour «comprendre» n'importe quelle expression régulière (les langages formels plus riches de type 0, 1 et 2 nécessitent quant à eux des dispositifs plus puissants pour être analysés). La dénomination d'expression régulière fait référence aux grammaires régulières qui sont le type de grammaires permettant d'engendrer les langages de type

157 Autres classes et interfaces à connaître des parenthèses et des accolades. Pour ce qui concerne Java, la syntaxe utilisée est particulièrement riche ; elle est très proche de celle de PERL 5, Python, JavaScript,... ; cette syntaxe est détaillée dans la documentation en-ligne de la classe Pattern. Pour un usage courant, il faut savoir que :. signifie un caractère quelconque ; [ ] définit un ensemble de caractères, exemple : [abc] a, b ou c ; [0-9] un chiffre ; [! ] définit un ensemble de caractères exclus, exemple : [!xy] n'importe quel caractère sauf x et y ; * signifie motif précédent répété zéro, une ou plusieurs fois ; *{n,m signifie motif précédent répété au moins n fois et au plus m fois, exemple : ab*{2,3c abbc ou abbbc ; + signifie motif précédent répété une ou plusieurs fois ;? signifie motif précédent répété zéro ou une fois ; correspond à un «ou» entre deux motifs. ATTENTION : ne pas confondre le concept d'expressions régulières et les «métacaractères»25 utilisés couramment dans les langages de commande (Shell UNIX, DOS,...) pour l'interprétation des noms de fichiers (les caractères utilisés sont presque les mêmes, l'usage est similaire mais la syntaxe est radicalement différente ; aussi, les expressions régulières constituent un dispositif beaucoup plus «puissant» pour filtrer des données textuelles). Exemple : d'erreurs) Lecture depuis le clavier (sans gestion Scanner scin = new Scanner(System.in); System.out.println("Entrez une chaine : "); String s = scin.next(); System.out.println("Entrez un entier : "); int n = scin.nextint(); System.out.println("s=" + s + ", n=" + n); Exemple : Lecture d'un fichier ligne par ligne avec affichage de son contenu sur l'écran try { Scanner sc = new Scanner(new FileReader("f.txt")); String ligne; while (sc.hasnextline()) { ligne = sc.nextline(); System.out.println(ligne); catch (FileNotFoundException e) { System.err.println(e); 25 - Autrement dit, les caractères suivants :? * [ ]! \ et ~. 169

158 Exemple : Lecture depuis le clavier avec utilisation d'un pattern et gestion d'erreurs Scanner sc = new Scanner(System.in); Pattern p = Pattern.compile( "[Yy]" ); try { String s1 = sc.next(p); // accepte uniquement Y ou y catch(inputmismatchexception e) { System.out.println("Y ou y attendu"); Conseil L'ensemble formé des classes Scanner et Pattern constitue l'outil à utiliser en priorité chaque fois qu'il faut analyser des données en mode texte dont la structure n'est pas complétement triviale, et ce, quelque soit la source de ces données (fichier, chaîne de caractères, socket,...) Toutefois, comme pour tout aspect un peu complexe de Java, il ne faut pas chercher à tout découvrir et encore moins tout mémoriser par avance. Mieux vaut adopter une démarche pragmatique consistant à bien mémoriser les principes puis, lorsqu'on en a besoin, rechercher les détails dans la documentation de référence (qu'il convient d'avoir toujours accessible, soit via Internet, soit en ayant une copie physique sur son disque dur). Tout aussi utile : penser à rechercher des exemples dans une base telle que (généralement plus efficace que de chercher un exemple avec Google). C. La classe Random Comparée à la méthode Math.random()26, la classe Random permet : de contrôler le caractère reproductible ou pas de la séquence générée ; d'obtenir des valeurs flottantes avec une distribution de type gaussienne plutôt qu'uniforme ; de générer autre chose que des double (e.g. des boolean, int, long, byte...). Exemple import java.util.random; //... Random r = new Random(); r.setseed(5); // pour rendre la séquence reproductible // (par défaut, la séquence est différente à chaque exécution) 26 - RAPPEL : Math.random() retourne un double dans l'intervalle [ [ ; des appels successifs produisent une série nouvelle à chaque exécution du programme ; la distribution des valeurs est «approximativement uniforme» cette fonction suffit tant qu'il s'agit de générer des double sans autre contrainte spécifique (caractère reproductible de la séquence générée, caractère «sécurisé» ou pas, contextes multi-threadé,...) 170

159 Autres classes et interfaces à connaître int x = r.nextint(); // x entier quelconque (2^32 valeurs possibles toutes équiprobables) int y = r.nextint(200); // y dans l'intervalle [ [ boolean b = r.nextboolean(); double d1 = r.nextdouble(); // d1 dans l'intervalle [ [ double d2 = r.nextgaussian(); // d2 double (valeur moyenne = 0.0 et déviation standard = 1) Remarque : Intérêt de contrôler le caractère reproductible de la séquence «aléatoire» Il est essentiel de pouvoir décider si la séquence de nombres «aléatoires» sera toujours la même ou pas lors d'exécutions répétées d'un programme. En effet, en phase de mise au point, il est beaucoup plus simple de debugger un code qui produit le même résultat à chaque exécution qu'un code qui se comporte différemment à chaque fois du fait de tirages aléatoire différents. Inversement, dans un contexte d'utilisation «normale», il est généralement préférable que les séquences générées à chaque exécution soient différentes (exemple : utilisation de nombres aléatoires pour faire varier des enchaînements dans un jeu). Pour s'assurer que la séquence aléatoire soit reproductible, il suffit d'invoquer le constructeur de la classe Random avec une «graine» identique ou d'invoquer la méthode setseed(), comme dans l' exemple ci-dessus. Complément : les classes ThreadLocalRandom et SecureRandom Deux autres classes sont disponibles en Java pour répondre à des besoins plus spécifiques : java.util.concurrent.threadlocalrandom : à privilégier lorsque plusieurs threads font un usage intensif de nombre aléatoires ; java.security.securerandom : à privilégier lorsqu'il est essentiel que chaque tirage «aléatoire» ne puisse en aucun cas être deviné sur la base des nombres produits précédemment, ou de toute autre information accessible lors l'exécution du programme27. D. La classe Objects La classe Objects28 contient une série de méthodes statiques utilitaires relatives aux objets. Les méthodes suivantes sont de simples variantes des méthodes équivalents de la classe Object : compare(), equals(), deepequals(),... [ elles permettent o1.equals(o2) ] juste d'écrire Objects.equals(o1, o2) à la place de D'autres méthodes de la classe Objects sont par contre fort pratiques lorsqu'une 27 - La cryptographie utilise fréquemment la génération de nombres aléatoires ; dans un tel contexte il convient d'utiliser la classe SecureRandom du paquetage java.security Objects avec un s, à ne pas confondre avec la classe Object (cf. la classe «Object» p 134). 171

160 variable de type référence peut (ou pas) contenir une référence nulle : hashcode(object o) retourne o.hashcode() ssi o est non-nul, et null sinon. tostring(object o, String msg) retourne o.tostring() ssi o est non-nul, et la chaîne msg sinon. Rappel Lorsqu'une référence o est nulle, une o.nomdemethode() ou o.nomattribut. exception est lancée si on exécute E. Localisation et internationalisation Plusieurs classes java sont disponibles pour faciliter «l'internationalisation» des programmes : classe Locale : permet l'identification d'une localisation en termes de langue et de région (utilise les normes ISO 639 et pour les langues et les alphabets et ISO 3166 pour les régions) ; classe ResourceBundle : permet d'isoler et gérer les données devant être localisées ; classe Formatter (cf. Entrées-sorties p 42) : permet l'affichage des nombres, dates, etc. selon la localisation ; classe Scanner (cf. Les classes Scanner et Pattern p 168) : permet la saisie des nombres selon la localisation ; classe Currency : permet la manipulation des symboles correspondants aux différentes devises (selon la norme internationale ISO ) ;... Définition : Localisation et internationalisation On appelle localisation l'adaptation d'un programme informatique à une région et/ou langue particulière. La localisation inclut différents aspects : la traduction de toute l'interface Homme-Machine ; la traduction des documentations (utilisateur, installation, etc.) ; la manière d'afficher (et saisir) les nombres, les dates, les monnaies, les températures, les distances, les surfaces, etc. ; etc. On appelle internationalisation l'effort consistant à rendre un programme informatique facile à localiser ce qui (en Java) passe typiquement par : abstraire à l'aide de la classe ResourceBundle tout ce qui doit être localisé (en particulier les fragments de textes utilisés pour l'interface Homme-Machine) ; stocker à l'extérieur du programme les versions pour chaque région/langue de tout ce qui a été isolé dans des ResourceBundle ; utiliser une instance de la classe Locale pour représenter la localisation correspondant à l'utilisateur ; utiliser des structures de données «localisables» et/ou afficher et saisir les données localisables en tant compte du contenu de la localisation La norme ISO 4217 définit une correspondance entre les noms, codes, et symboles des différentes monnaies. Ainsi, le code numérique pour l'euro est 978, le code sous forme de chaîne est "EUR" et le symbole corespondant ' '. 172

161 Autres classes et interfaces à connaître Conseil Penser au tutoriel d'oracle30 (sentier «Internationalization») pour approfondir ces notions de localisation et d'internationalisation, et apprendre comment les mettre en œuvre en Java avec quelques exemples

162 Documentation automatique (javadoc) XVI - XVI Mise en œuvre : Nécessite d'insérer dans le code des commentaires spécifiques selon la syntaxe : /** bla-bla... (sur une ou plusieurs lignes) */ javadoc NomClasse.java produit automatiquement décrivant la classe et intégrant ces commentaires racine = index.html des fichiers HTML Remarque Les commentaires javadoc se placent juste avant les déclarations de : - packages - classes - interfaces - méthodes - attributs Par défaut, seuls les éléments publics et protégés apparaissent (car ce sont les seuls qu'ont à connaître les utilisateurs de la classe) Complément : Tags dans les commentaires Les commentaires javadoc peuvent comporter des «tags» qui seront formatés de manière spécifique. Ils commencent en début de ligne et vont jusqu'à fin de ligne nom (pour une classe ou nom description (pour une méthode: commentaire sur un de ses description (pour une méthode : commentaire sur ce qui est nom description (pour une méthode : commentaire sur un type d'exception potentiellement NomClasse (lien hypertexte vers la documentation de la classe NomClasse#nomMethode (idem, mais lien vers l'endroit où est décrite la méthode nommethode) 175

163 Attention Javadoc est conçu pour documenter des packages/classes/interfaces Java afin de faciliter leur utilisation lors de l'écriture de programmes. Le lecteur de cette documentation est donc, typiquement, un programmeur qui souhaite utiliser un code Java pré-existant le plus rapidement possible (sans forcément en connaître tous les détails). Javadoc n'est pas conçu pour : documenter les détails d'implantation à l'intérieur des méthodes, ou les choix techniques effectués lors de la mise au point du programme utiliser pour cela les commentaires ordinaires de Java ; produire un mode d'emploi du programme à l'intention de l'utilisateur final pour cela, joindre une notice au programme et/ou prévoir une page d'aide dans l'ihm. 176

164 XVII - Annotations XVII Annotations 177 Annotations standards (prédéfinies) en Java 178 Définition d'annotations 178 Le «checker framework» 179 A. Annotations Définition Métadonnées attachées à un élément du code source (se placent juste avant l'élément annoté). Ces métadonnées peuvent être exploitées : lors de la compilation (vérifications sémantiques, optimisations,...) ; lors de l'exécution par la machine virtuelle Java (optimisations) ; lors de l'exécution par le code (via l'introspection) ; par des outils externes (javadoc, outils d'analyses, d'optimisation,...) Remarque Tout ou presque peut être annoté dans un code java (déclarations, affectations, invocations de méthodes,...) Syntaxe 1. annotations marqueurs 2. annotations paramétrées 3. annotations multi-paramétrées = "valeur1", attribut2 = "valeur2",...) NOTA-BENE : chaque paramètre a un type (int, double, boolean, String, tableau,...) Exemple class Mere { public void demarrer() {... public boolean ajuster(double[]) {... class Fille extends Mere public void demarer() {

165 // erreur de compilation «grâce» à l'annotation! public boolean ajuster(double) {... // erreur de compilation «grâce» à l'annotation! Usages principaux permet de spécifier plus formellement certains aspects du code typage plus rigoureux et/ou plus précis, possibilité de vérifications automatiques additionnelles ; code plus fiable ; permet d'expliciter l'intention du programmeur code plus lisible, plus facile à maintenir ; permet d'inclure dans le code des directives destinées au compilateur, à la JVM ou à des outils manipulant le code source ou le bytecode. B. Annotations standards (prédéfinies) @SupressWarnings({"deprecation","unchecked",...) C. Définition d'annotations Possibilité de définir ses propres annotations accessibles lors de l'exécution (introspection) ou depuis des outils externes. Exemple : Définition d'une nouvelle annotation avant son utilisation dans le code MonAnnotation { String arg1(); int arg2(); int arg3() default 0; String[] arg4(); arg2=7, arg4={"a", "b") public class MaClasse { //... Complément : Annotations relatives aux définitions d'annotations Plusieurs annotations standards de Java concernent la définition des annotations : 178

166 déclenche l'inclusion du contenu de l'annotation dans la documentation produite par javadoc31 déclenche l'inclusion du contenu de l'annotation dans le bytecode ElementType.METHOD,...) spécifie les éléments du code compatibles avec cette annotation ;... D. Le «checker framework» Permet d'étendre l'ensemble des vérifications effectuées sur le code par rapport à ce que réalise le compilateur Java. Intérêt : détecter/prévenir de nombreux bugs ; expliciter avec précision l'intention du programmeur. Mise en œuvre sous Java 8 : non fourni en standard, à télécharger/installer ; s'utilise ensuite sous forme d'un «plugin» dans le compilateur java (disponible pour javac, Eclipse et la plupart des compilateurs Java) Annotations définies par le checker L'utilisation systématique de telles annotations est une alternative à l'usage de la notation /**... */ ; elle peut permettre de structurer/formaliser le contenu des commentaires produits par javadoc ; elle permet en outre leur inclusion dans le bytecode produit en cas d'utilisation combinée 179

167 Graphisme et Interface HommeMachine (IHM) XVIII - XVIII Introduction 181 Composants prédéfinis d'awt 182 Utilisation des conteneurs 184 Gestionnaires de présentation 184 Événements et programmation événementielle 186 Dessiner 192 Couleurs 193 Polices de caractères 194 Images 194 Dimensions de l'écran et des composants 195 Applet vs application 196 Ecrire une applet 196 Ecrire une application graphique 201 Swing 203 Pour aller plus loin A. Introduction Deux sortes de programmes graphiques en Java 1. Les appliquettes (Applet) Elles peuvent fonctionner par le truchement d'un navigateur : Firefox, IE, Safari, Chrome,... ou via un programme spécifique : appletviewer 2. Les applications indépendantes Lancées exactement comme n'importe quelle application (non graphique) Principaux packages java à disposition java.awt : composants et outils graphiques, audios, vidéos,... java.awt.event : gestion des événements java.applet : création d'applets javax.swing : étend java.awt (plus complet mais plus complexe à maîtriser qu'awt) NOTA-BENE : il existe d'autres packages pour sophistiquées : Java2D, JavaFX, SWT, Java3D,... faciliter la réalisation d'ihms 181

168 Ce qu'il faut pour créer une IHM Des composants graphiques élémentaires Un (ou des) conteneur(s) Un gestionnaire de présentation associé à chaque conteneur (éventuellement par défaut) Si besoin, des dessins (points, courbes, images,...) Ajouter les composants graphiques au(x) conteneur(s) par l'intermédiaire du gestionnaire de présentation Ecouter les événements associés aux composants graphiques (clavier, souris, focus, choix,...) B. Composants prédéfinis d'awt AWT = Abstract Window Toolkit (boîte à outils standard en Java pour construire des IHMs) Complément : Swing et SWT Au delà d'awt il existe au moins deux autres boîtes à outils très largement utilisées pour construire des IHMs en Java : Swing : fait partie du standard JAVA ; s'appuie sur AWT mais ajoute de nombreux composants et fonctionnalités sans remettre en cause les principes généraux d'awt (modèle des événements) ; SWT : boîte à outils développée en dehors du standard Java mais largement utilisée ; proposé comme alternative à l'ensemble AWT+Swing. NOTA-BENE : Eclipse est écrit en Java avec une IHM programmée avec le package SWT. Composants «de base» et «conteneurs» Les composants de base (boutons, etc.) dérivent, pour la plupart, de la classe abstraite Component Les conteneurs dérivent de la classe abstraite Container 182

169 Graphisme et Interface Homme-Machine (IHM) Conteneurs prédéfinis d'awt Nom Fonction Panel conteneur de base ScrollPane conteneur pour composant unique à barre de défilement Frame fenêtre Window fenêtre sans titre ni barre de défilement Dialog fenêtre popup «modale» FileDialog fenêtre de sélection de fichier Applet applet (hérite de Panel, voir plus loin) Autres composants prédéfinis d'awt Nom Fonction Button bouton (cliquable) Canvas zone pour dessiner Checkbox case à cocher Label texte constant CheckboxGroup pour grouper des choix exclusifs MenuBar barre de menu Menu menu MenuItem item de menu CheckboxMenuItem item de menu à cocher 183

170 Nom Fonction Choice liste déroulante de choix exclusifs List liste de choix exclusifs ou non ScrollBar barre de défilement TextField zone de texte modifiable (une ligne) TextArea idem (mais sur plusieurs lignes) C. Utilisation des conteneurs Pour être visible, un composant «de base» doit avoir été ajouté à un conteneur par la méthode add() : c.add(component co) : ajoute le composant co au conteneur c c.add(component co, Object contrainte) : idem, avec une contrainte pour le gestionnaire de présentation Exemple : c.add(co, BorderLayout.WEST) c.add(component co, int i) : place le composant en i-ème position (sauf pour BorderLayout) Autres méthodes disponibles dans les classes conteneurs : c.getcomponentcount() : renvoie le nombre de composants dans c c.getcomponents() : renvoie le tableau des composants dans c c.getcomponentcount(int n) : renvoie le nième composant dans c c.remove(int n) : retire de c le nième composant c.removeall() : retire tous les composants de c c.validate() : recalcule la disposition des composants (et composants éventuels) Et bien d'autres! Voir la documentation de la classe Container Attention : des sous- la méthode validate() Une fois un conteneur et ses composants visibles, il est toujours possible d'y ajouter ou supprimer des composants via les méthodes add(), remove(), removeall(),... L'effet de ces modifications ne sera toutefois pas visible avant appel de la méthode validate(). En effet, pour des raisons de performance, le calcul de la disposition des composants dans le conteneur n'est pas effectué automatiquement après tout changement. Le calcul peut en effet être gourmand en temps de calcul lorsque des conteneurs sont imbriquées sur plusieurs niveaux de profondeur. Par ailleurs, il est fréquent de faire plusieurs appels successifs à remove() et add() lorsqu'on modifie le contenu d'un conteneur. L'invocation de validate() est donc nécessaire pour indiquer à Java qu'on a fini de modifier le conteneur et qu'on souhaite rendre visible ces modifications. D. Gestionnaires de présentation Principe La disposition des composants dans un conteneur est assurée par un «gestionnaire de présentation» ou «Layout Manager» Chaque conteneur a son propre LayoutManager qui place automatiquement les 184

171 Graphisme et Interface Homme-Machine (IHM) composants qu'il contient Plusieurs LayoutManagers sont pré-définis dans le package AWT, ils différent par leur manière de disposer les composants dans «leur» conteneur Pour affecter un gestionnaire à un conteneur : c.setlayout(new GridLayout(2,4)); Remarque L'interface gestionnaire de présentation s'appelle LayoutManager, mais les méthodes se nomment setlayout(...) et getlayout() [sans Manager après Layout]. Il est possible de spécifier un gestionnaire de présentation lors de la création d'un Panel : Panel c = new Panel(new GridLayout(2,4)); (pour un Frame ce n'est pas possible, il faut impérativement le créer puis invoquer setlayout()). FlowLayout Fonctionnement du FlowLayout : de gauche à droite puis de haut en bas en centrant, taille des composants fixe BorderLayout Fonctionnement du BorderLayout : 5 places prédéfinies, tailles ajustées selon la «région» GridLayout Fonctionnement du GridLayout : Tableau en lignes, colonnes. Ajout par ligne puis par colonne 185

172 Remarque Il existe d'autres gestionnaires de présentation pré-définis dans AWT : CardLayout, GridBagLayout,... Il en existe d'autres encore dans Swing (voir plus loin). Complément : Gestionnaire de présentation par défaut Si on n'affecte pas de LayoutManager à un conteneur via la métode setlayout(), Java lui en affecte un par défaut : Pour les instances de Panel et Applet gestionnaire par défaut = FlowLayout Pour les instances de Window et Frame gestionnaire par défaut = BorderLayout Exemple avec panel imbriqué Dans cet exemple, différents conteneurs utilisent des gestionnaires de présentation différents pour obtenir une disposition particulière : Fenêtre englobante : BorderLayout pour avoir les Labels au nord au sud et la grille au centre Création d'un Panel pour la grille de boutons : GridLayout(5,5) pour avoir des boutons de même taille E. Événements et programmation événementielle En Java, la réactivité des boutons, listes, menu, clic souris, déplacement souris, etc... doit être assurée par une gestion d'événements : les composants graphiques émettent des événements en réaction à certaines actions de l'utilisateur ; le programme réagit alors à ces événements, ou pas, selon ce que le programmeur aura décidé d'inclure dans son code. Cela conduit à un style de programmation qui n'est plus «impératif» (séquentiel selon un ordre des instructions déterminé par l'auteur du programme) mais dirigé par les événements, on parle alors de «programmation événementielle» En pratique, le programmeur sélectionne par avance les catégories d'événements qui l'intéresse, puis écrit (dans des méthodes ad hoc) les fragments de code qui seront invoqués si/quand tel ou tel événement se produit. 186

Institut Supérieure Aux Etudes Technologiques De Nabeul. Département Informatique

Institut Supérieure Aux Etudes Technologiques De Nabeul. Département Informatique Institut Supérieure Aux Etudes Technologiques De Nabeul Département Informatique Support de Programmation Java Préparé par Mlle Imene Sghaier 2006-2007 Chapitre 1 Introduction au langage de programmation

Plus en détail

Introduction à Java. Matthieu Herrb CNRS-LAAS. Mars 2014. http://homepages.laas.fr/matthieu/cours/java/java.pdf

Introduction à Java. Matthieu Herrb CNRS-LAAS. Mars 2014. http://homepages.laas.fr/matthieu/cours/java/java.pdf Introduction à Java Matthieu Herrb CNRS-LAAS http://homepages.laas.fr/matthieu/cours/java/java.pdf Mars 2014 Plan 1 Concepts 2 Éléments du langage 3 Classes et objets 4 Packages 2/28 Histoire et motivations

Plus en détail

Info0101 Intro. à l'algorithmique et à la programmation. Cours 3. Le langage Java

Info0101 Intro. à l'algorithmique et à la programmation. Cours 3. Le langage Java Info0101 Intro. à l'algorithmique et à la programmation Cours 3 Le langage Java Pierre Delisle, Cyril Rabat et Christophe Jaillet Université de Reims Champagne-Ardenne Département de Mathématiques et Informatique

Plus en détail

Annexe : La Programmation Informatique

Annexe : La Programmation Informatique GLOSSAIRE Table des matières La Programmation...2 Les langages de programmation...2 Java...2 La programmation orientée objet...2 Classe et Objet...3 API et Bibliothèque Logicielle...3 Environnement de

Plus en détail

Programmer en JAVA. par Tama (tama@via.ecp.fr( tama@via.ecp.fr)

Programmer en JAVA. par Tama (tama@via.ecp.fr( tama@via.ecp.fr) Programmer en JAVA par Tama (tama@via.ecp.fr( tama@via.ecp.fr) Plan 1. Présentation de Java 2. Les bases du langage 3. Concepts avancés 4. Documentation 5. Index des mots-clés 6. Les erreurs fréquentes

Plus en détail

as Architecture des Systèmes d Information

as Architecture des Systèmes d Information Plan Plan Programmation - Introduction - Nicolas Malandain March 14, 2005 Introduction à Java 1 Introduction Présentation Caractéristiques Le langage Java 2 Types et Variables Types simples Types complexes

Plus en détail

Initiation à JAVA et à la programmation objet. raphael.bolze@ens-lyon.fr

Initiation à JAVA et à la programmation objet. raphael.bolze@ens-lyon.fr Initiation à JAVA et à la programmation objet raphael.bolze@ens-lyon.fr O b j e c t i f s Découvrir un langage de programmation objet. Découvrir l'environnement java Découvrir les concepts de la programmation

Plus en détail

UEO11 COURS/TD 1. nombres entiers et réels codés en mémoire centrale. Caractères alphabétiques et caractères spéciaux.

UEO11 COURS/TD 1. nombres entiers et réels codés en mémoire centrale. Caractères alphabétiques et caractères spéciaux. UEO11 COURS/TD 1 Contenu du semestre Cours et TDs sont intégrés L objectif de ce cours équivalent a 6h de cours, 10h de TD et 8h de TP est le suivant : - initiation à l algorithmique - notions de bases

Plus en détail

Évaluation et implémentation des langages

Évaluation et implémentation des langages Évaluation et implémentation des langages Les langages de programmation et le processus de programmation Critères de conception et d évaluation des langages de programmation Les fondations de l implémentation

Plus en détail

Généralités sur le Langage Java et éléments syntaxiques.

Généralités sur le Langage Java et éléments syntaxiques. Généralités sur le Langage Java et éléments syntaxiques. Généralités sur le Langage Java et éléments syntaxiques....1 Introduction...1 Genéralité sur le langage Java....1 Syntaxe de base du Langage...

Plus en détail

Cours 1 : Introduction. Langages objets. but du module. contrôle des connaissances. Pourquoi Java? présentation du module. Présentation de Java

Cours 1 : Introduction. Langages objets. but du module. contrôle des connaissances. Pourquoi Java? présentation du module. Présentation de Java Langages objets Introduction M2 Pro CCI, Informatique Emmanuel Waller, LRI, Orsay présentation du module logistique 12 blocs de 4h + 1 bloc 2h = 50h 1h15 cours, 45mn exercices table, 2h TD machine page

Plus en détail

UE Programmation Impérative Licence 2ème Année 2014 2015

UE Programmation Impérative Licence 2ème Année 2014 2015 UE Programmation Impérative Licence 2 ème Année 2014 2015 Informations pratiques Équipe Pédagogique Florence Cloppet Neilze Dorta Nicolas Loménie prenom.nom@mi.parisdescartes.fr 2 Programmation Impérative

Plus en détail

Plan du cours. Historique du langage http://www.oracle.com/technetwork/java/index.html. Nouveautés de Java 7

Plan du cours. Historique du langage http://www.oracle.com/technetwork/java/index.html. Nouveautés de Java 7 Université Lumière Lyon 2 Faculté de Sciences Economiques et Gestion KHARKIV National University of Economic Introduction au Langage Java Master Informatique 1 ère année Julien Velcin http://mediamining.univ-lyon2.fr/velcin

Plus en détail

Cours intensif Java. 1er cours: de C à Java. Enrica DUCHI LIAFA, Paris 7. Septembre 2009. Enrica.Duchi@liafa.jussieu.fr

Cours intensif Java. 1er cours: de C à Java. Enrica DUCHI LIAFA, Paris 7. Septembre 2009. Enrica.Duchi@liafa.jussieu.fr . Cours intensif Java 1er cours: de C à Java Septembre 2009 Enrica DUCHI LIAFA, Paris 7 Enrica.Duchi@liafa.jussieu.fr LANGAGES DE PROGRAMMATION Pour exécuter un algorithme sur un ordinateur il faut le

Plus en détail

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP COURS PROGRAMMATION INITIATION AU LANGAGE C SUR MICROCONTROLEUR PIC page 1 / 7 INITIATION AU LANGAGE C SUR PIC DE MICROSHIP I. Historique du langage C 1972 : naissance du C dans les laboratoires BELL par

Plus en détail

Éléments de programmation et introduction à Java

Éléments de programmation et introduction à Java Éléments de programmation et introduction à Java Jean-Baptiste Vioix (jean-baptiste.vioix@iut-dijon.u-bourgogne.fr) IUT de Dijon-Auxerre - LE2I http://jb.vioix.free.fr 1-20 Les différents langages informatiques

Plus en détail

Pour signifier qu'une classe fille hérite d'une classe mère, on utilise le mot clé extends class fille extends mère

Pour signifier qu'une classe fille hérite d'une classe mère, on utilise le mot clé extends class fille extends mère L'héritage et le polymorphisme en Java Pour signifier qu'une classe fille hérite d'une classe mère, on utilise le mot clé extends class fille extends mère En java, toutes les classes sont dérivée de la

Plus en détail

Anne Tasso. Java. Le livre de. premier langage. 10 e édition. Avec 109 exercices corrigés. Groupe Eyrolles, 2000-2015, ISBN : 978-2-212-14154-2

Anne Tasso. Java. Le livre de. premier langage. 10 e édition. Avec 109 exercices corrigés. Groupe Eyrolles, 2000-2015, ISBN : 978-2-212-14154-2 Anne Tasso Java Le livre de premier langage 10 e édition Avec 109 exercices corrigés Groupe Eyrolles, 2000-2015, ISBN : 978-2-212-14154-2 Table des matières Avant-propos Organisation de l ouvrage..............................

Plus en détail

Java - la plateforme

Java - la plateforme Java - la plateforme Java la plateforme Java? VM GC JIT Java Aujourd'hui 3 environnements d'exécutions différents Java ME (Micro Edition) pour PDA, téléphone Android (Java SE moins certain paquetages)

Plus en détail

TP1 : Initiation à Java et Eclipse

TP1 : Initiation à Java et Eclipse TP1 : Initiation à Java et Eclipse 1 TP1 : Initiation à Java et Eclipse Systèmes d Exploitation Avancés I. Objectifs du TP Ce TP est une introduction au langage Java. Il vous permettra de comprendre les

Plus en détail

Structure d un programme et Compilation Notions de classe et d objet Syntaxe

Structure d un programme et Compilation Notions de classe et d objet Syntaxe Cours1 Structure d un programme et Compilation Notions de classe et d objet Syntaxe POO 1 Programmation Orientée Objet Un ensemble d objet qui communiquent Pourquoi POO Conception abstraction sur les types

Plus en détail

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile Dans ce TP, vous apprendrez à définir le type abstrait Pile, à le programmer en Java à l aide d une interface

Plus en détail

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

INTRODUCTION A JAVA. Fichier en langage machine Exécutable INTRODUCTION A JAVA JAVA est un langage orienté-objet pur. Il ressemble beaucoup à C++ au niveau de la syntaxe. En revanche, ces deux langages sont très différents dans leur structure (organisation du

Plus en détail

La technologie Java Card TM

La technologie Java Card TM Présentation interne au CESTI La technologie Java Card TM sauveron@labri.u-bordeaux.fr http://dept-info.labri.u-bordeaux.fr/~sauveron 8 novembre 2002 Plan Qu est ce que Java Card? Historique Les avantages

Plus en détail

Une introduction à Java

Une introduction à Java Une introduction à Java IFT 287 (Semaine 1) UNIVERSITÉ DE SHERBROOKE 1 Java - Historique Développé par Sun Microsystems en 1994 Inventeur James Gosling (canadien!) Objectif langage sûr (fortement typé)

Plus en détail

JAVA 8. JAVA 8 - Les fondamentaux du langage. Les fondamentaux du langage Java. Avec exercices pratiques et corrigés JAVA 8 29,90.

JAVA 8. JAVA 8 - Les fondamentaux du langage. Les fondamentaux du langage Java. Avec exercices pratiques et corrigés JAVA 8 29,90. Analyste et développeur pendant plus de 10 ans, Thierry GROUSSARD s est ensuite orienté vers la formation et plus particulièrement dans le domaine du développement. Sa connaissance approfondie des besoins

Plus en détail

Langage Java. Classe de première SI

Langage Java. Classe de première SI Langage Java Table des matières 1. Premiers pas...2 1.1. Introduction...2 1.2. Mon premier programme...2 1.3. Les commentaires...2 2. Les variables et les opérateurs...2 3. La classe Scanner...3 4. Les

Plus en détail

Cours 1: Java et les objets

Cours 1: Java et les objets Ressources Les interface homme-machine et le langage Java DUT première année Henri Garreta, Faculté des Sciences (Luminy) Cyril Pain-Barre & Sébastien Nedjar, IUT d Aix-Marseille (Aix) Cours 1: infodoc.iut.univ-aix.fr/~ihm/

Plus en détail

Chapitre I Notions de base et outils de travail

Chapitre I Notions de base et outils de travail Chapitre I Notions de base et outils de travail Objectifs Connaître les principes fondateurs et l historique du langage Java S informer des principales caractéristiques du langage Java Connaître l environnement

Plus en détail

Héritage presque multiple en Java (1/2)

Héritage presque multiple en Java (1/2) Héritage presque multiple en Java (1/2) Utiliser deux classes ou plus dans la définition d'une nouvelle classe peut se faire par composition. class Etudiant{ int numero; Diplome d; float passeexamen(examen

Plus en détail

Cours d introduction à l informatique. Partie 2 : Comment écrire un algorithme? Qu est-ce qu une variable? Expressions et instructions

Cours d introduction à l informatique. Partie 2 : Comment écrire un algorithme? Qu est-ce qu une variable? Expressions et instructions Cours d introduction à l informatique Partie 2 : Comment écrire un algorithme? Qu est-ce qu une variable? Expressions et instructions Qu est-ce qu un Une recette de cuisine algorithme? Protocole expérimental

Plus en détail

Licence ST Université Claude Bernard Lyon I LIF1 : Algorithmique et Programmation C Bases du langage C 1 Conclusion de la dernière fois Introduction de l algorithmique générale pour permettre de traiter

Plus en détail

Langage et Concepts de ProgrammationOrientée-Objet 1 / 40

Langage et Concepts de ProgrammationOrientée-Objet 1 / 40 Déroulement du cours Introduction Concepts Java Remarques Langage et Concepts de Programmation Orientée-Objet Gauthier Picard École Nationale Supérieure des Mines de Saint-Étienne gauthier.picard@emse.fr

Plus en détail

INITIATION AU LANGAGE JAVA

INITIATION AU LANGAGE JAVA INITIATION AU LANGAGE JAVA I. Présentation 1.1 Historique : Au début des années 90, Sun travaillait sur un projet visant à concevoir des logiciels simples et performants exécutés dans des PDA (Personnal

Plus en détail

Vulgarisation Java EE Java EE, c est quoi?

Vulgarisation Java EE Java EE, c est quoi? Paris, le 1 Février 2012 Vulgarisation Java EE Java EE, c est quoi? Sommaire Qu est ce que Java? Types d applications Java Environnements Java Versions de Java Java EE, c est quoi finalement? Standards

Plus en détail

Machines Virtuelles. et bazard autour. Rémi Forax

Machines Virtuelles. et bazard autour. Rémi Forax Machines Virtuelles et bazard autour Rémi Forax Avant propos Quelle est la complexité du code ci-dessous? Avec un processeur à 1Ghz, combien de temps le calcul prendra t'il? public static void main(string[]

Plus en détail

Java Licence Professionnelle CISII, 2009-2010

Java Licence Professionnelle CISII, 2009-2010 Licence Professionnelle CISII, 2009-2010 Cours 1 : Introduction à Java A. Belaïd abelaid@loria.fr Cours disponible sur le site : http://www.loria.fr/~abelaid puis Teaching 1 Fonctionnement 12 séances :

Plus en détail

IN 102 - Cours 1. 1 Informatique, calculateurs. 2 Un premier programme en C

IN 102 - Cours 1. 1 Informatique, calculateurs. 2 Un premier programme en C IN 102 - Cours 1 Qu on le veuille ou non, les systèmes informatisés sont désormais omniprésents. Même si ne vous destinez pas à l informatique, vous avez de très grandes chances d y être confrontés en

Plus en détail

Partie 1. Professeur : Haouati Abdelali. CPGE Lycée Omar Ibn Lkhattab - Meknès www.haouati.com haouaticpge@gmail.com

Partie 1. Professeur : Haouati Abdelali. CPGE Lycée Omar Ibn Lkhattab - Meknès www.haouati.com haouaticpge@gmail.com Partie 1 Professeur : Haouati Abdelali CPGE Lycée Omar Ibn Lkhattab - Meknès www.haouati.com haouaticpge@gmail.com Partie I : Généralités et algorithmique de base 1. Environnement matériel et logiciel

Plus en détail

Informatique Générale

Informatique Générale Informatique Générale Guillaume Hutzler Laboratoire IBISC (Informatique Biologie Intégrative et Systèmes Complexes) guillaume.hutzler@ibisc.univ-evry.fr Cours Dokeos 625 http://www.ens.univ-evry.fr/modx/dokeos.html

Plus en détail

Codage d information. Codage d information : -Définition-

Codage d information. Codage d information : -Définition- Introduction Plan Systèmes de numération et Représentation des nombres Systèmes de numération Système de numération décimale Représentation dans une base b Représentation binaire, Octale et Hexadécimale

Plus en détail

Chapitre 2. Classes et objets

Chapitre 2. Classes et objets Chapitre 2: Classes et Objets 1/10 Chapitre 2 Classes et objets Chapitre 2: Classes et Objets 2/10 Approche Orientée Objet Idée de base de A.O.O. repose sur l'observation de la façon dont nous procédons

Plus en détail

Programmation Orientée Objet

Programmation Orientée Objet Programmation Orientée Objet Mohamed Tounsi Institut Supérieur d'informatique et de Multimédia Sfax Septembre 2014 Mohamed Tounsi (ISIMS) Programmation Orientée Objet Septembre 2014 1 / 16 Responsable

Plus en détail

MICROINFORMATIQUE NOTE D APPLICATION 1 (REV. 2011) ARITHMETIQUE EN ASSEMBLEUR ET EN C

MICROINFORMATIQUE NOTE D APPLICATION 1 (REV. 2011) ARITHMETIQUE EN ASSEMBLEUR ET EN C Haute Ecole d Ingénierie et de Gestion Du Canton du Vaud MICROINFORMATIQUE NOTE D APPLICATION 1 (REV. 2011) ARITHMETIQUE EN ASSEMBLEUR ET EN C Programmation en mode simulation 1. DOCUMENTS DE RÉFÉRENCE...

Plus en détail

INF 321 : mémento de la syntaxe de Java

INF 321 : mémento de la syntaxe de Java INF 321 : mémento de la syntaxe de Java Table des matières 1 La structure générale d un programme 3 2 Les composants élémentaires de Java 3 2.1 Les identificateurs.................................. 3 2.2

Plus en détail

La carte à puce. Jean-Philippe Babau

La carte à puce. Jean-Philippe Babau La carte à puce Jean-Philippe Babau Département Informatique INSA Lyon Certains éléments de cette présentation sont issus de documents Gemplus Research Group 1 Introduction Carte à puce de plus en plus

Plus en détail

Représentation des Nombres

Représentation des Nombres Chapitre 5 Représentation des Nombres 5. Representation des entiers 5.. Principe des représentations en base b Base L entier écrit 344 correspond a 3 mille + 4 cent + dix + 4. Plus généralement a n a n...

Plus en détail

Bases de programmation. Cours 5. Structurer les données

Bases de programmation. Cours 5. Structurer les données Bases de programmation. Cours 5. Structurer les données Pierre Boudes 1 er décembre 2014 This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License. Types char et

Plus en détail

Encapsulation. L'encapsulation consiste à rendre les membres d'un objet plus ou moins visibles pour les autres objets.

Encapsulation. L'encapsulation consiste à rendre les membres d'un objet plus ou moins visibles pour les autres objets. Encapsulation L'encapsulation consiste à rendre les membres d'un objet plus ou moins visibles pour les autres objets. La visibilité dépend des membres : certains membres peuvent être visibles et d'autres

Plus en détail

INF2015 Développement de logiciels dans un environnement Agile. Examen intra 20 février 2014 17:30 à 20:30

INF2015 Développement de logiciels dans un environnement Agile. Examen intra 20 février 2014 17:30 à 20:30 Examen intra 20 février 2014 17:30 à 20:30 Nom, prénom : Code permanent : Répondez directement sur le questionnaire. Question #1 5% Quelle influence peut avoir le typage dynamique sur la maintenabilité

Plus en détail

Java c est quoi? Java pourquoi?

Java c est quoi? Java pourquoi? Grandes lignes du cours Cours JAVA : Le bases du langage Java. Version 3.02 Julien Sopena 1 1 julien.sopena@lip6.fr Équipe REGAL - INRIA Rocquencourt LIP6 - Université Pierre et Marie Curie Licence professionnelle

Plus en détail

Chapitre 1 : Introduction aux bases de données

Chapitre 1 : Introduction aux bases de données Chapitre 1 : Introduction aux bases de données Les Bases de Données occupent aujourd'hui une place de plus en plus importante dans les systèmes informatiques. Les Systèmes de Gestion de Bases de Données

Plus en détail

Une version javascript sera disponible directement dans le cours prochainement.

Une version javascript sera disponible directement dans le cours prochainement. Author : Cédric Vanconingsloo Ce cours est principalement axé sur la compréhension du fonctionnement d'un ordinateur et l'étude du seul langage qu'il connaisse, le binaire. De ce fait, le cours est relativement

Plus en détail

Diagramme de classes

Diagramme de classes Diagramme de classes Un diagramme de classes décrit les classes et leurs relations (associations, généralisation/spécialisation, ). classe association méthodes attributs héritage Diagramme de classes :

Plus en détail

Logiciel de Base. I. Représentation des nombres

Logiciel de Base. I. Représentation des nombres Logiciel de Base (A1-06/07) Léon Mugwaneza ESIL/Dépt. Informatique (bureau A118) mugwaneza@univmed.fr I. Représentation des nombres Codage et représentation de l'information Information externe formats

Plus en détail

ALGORITHMIQUE ET PROGRAMMATION En C

ALGORITHMIQUE ET PROGRAMMATION En C Objectifs ALGORITHMIQUE ET PROGRAMMATION Une façon de raisonner Automatiser la résolution de problèmes Maîtriser les concepts de l algorithmique Pas faire des spécialistes d un langage Pierre TELLIER 2

Plus en détail

Programmation en Java IUT GEII (MC-II1) 1

Programmation en Java IUT GEII (MC-II1) 1 Programmation en Java IUT GEII (MC-II1) 1 Christophe BLANC - Paul CHECCHIN IUT Montluçon Université Blaise Pascal Novembre 2009 Christophe BLANC - Paul CHECCHIN Programmation en Java IUT GEII (MC-II1)

Plus en détail

LANGAGUE JAVA. Public Développeurs souhaitant étendre leur panel de langages de programmation

LANGAGUE JAVA. Public Développeurs souhaitant étendre leur panel de langages de programmation ING 01 LANGAGUE JAVA Durée : 21 heures 1090 HT / jour Dates : à définir en 2012 Concevoir et développer des programmes en langage Java Comprendre le fonctionnement de la machine virtuelle S approprier

Plus en détail

Chapitre VI- La validation de la composition.

Chapitre VI- La validation de la composition. Chapitre VI- La validation de la composition. Objectifs du chapitre : Expliquer les conséquences de l utilisation de règles de typage souples dans SEP. Présenter le mécanisme de validation des connexions

Plus en détail

Cours 1 : La compilation

Cours 1 : La compilation /38 Interprétation des programmes Cours 1 : La compilation Yann Régis-Gianas yrg@pps.univ-paris-diderot.fr PPS - Université Denis Diderot Paris 7 2/38 Qu est-ce que la compilation? Vous avez tous déjà

Plus en détail

Base de l'informatique. Généralité et Architecture Le système d'exploitation Les logiciels Le réseau et l'extérieur (WEB)

Base de l'informatique. Généralité et Architecture Le système d'exploitation Les logiciels Le réseau et l'extérieur (WEB) Base de l'informatique Généralité et Architecture Le système d'exploitation Les logiciels Le réseau et l'extérieur (WEB) Généralité Comment fonctionne un ordinateur? Nous définirons 3 couches Le matériel

Plus en détail

Programmation C. Apprendre à développer des programmes simples dans le langage C

Programmation C. Apprendre à développer des programmes simples dans le langage C Programmation C Apprendre à développer des programmes simples dans le langage C Notes de cours sont disponibles sur http://astro.u-strasbg.fr/scyon/stusm (attention les majuscules sont importantes) Modalités

Plus en détail

C++ COURS N 2 : CLASSES, DONNÉES ET FONCTIONS MEMBRES Classes et objets en C++ Membres d'une classe Spécification d'une classe Codage du comportement

C++ COURS N 2 : CLASSES, DONNÉES ET FONCTIONS MEMBRES Classes et objets en C++ Membres d'une classe Spécification d'une classe Codage du comportement C++ COURS N 2 : CLASSES, DONNÉES ET FONCTIONS MEMBRES Classes et objets en C++ Membres d'une classe Spécification d'une classe Codage du comportement des objets d'une classe Utilisation d'une classe Droit

Plus en détail

ACTIVITÉ DE PROGRAMMATION

ACTIVITÉ DE PROGRAMMATION ACTIVITÉ DE PROGRAMMATION The purpose of the Implementation Process is to realize a specified system element. ISO/IEC 12207 Sébastien Adam Une introduction 2 Introduction Ø Contenu Utilité de l ordinateur,

Plus en détail

Chapitre 10 Arithmétique réelle

Chapitre 10 Arithmétique réelle Chapitre 10 Arithmétique réelle Jean Privat Université du Québec à Montréal INF2170 Organisation des ordinateurs et assembleur Automne 2013 Jean Privat (UQAM) 10 Arithmétique réelle INF2170 Automne 2013

Plus en détail

Polycopié Cours Programmation Orientée Objet sous Java Programme : Filière SMI S5

Polycopié Cours Programmation Orientée Objet sous Java Programme : Filière SMI S5 UNIVERISTE MOHAMMED PREMIER Faculté des Sciences d Oujda Oujda - Maroc Polycopié Cours Programmation Orientée Objet sous Java Programme : Filière SMI S5 Pr. El Mostafa DAOUDI Département de Mathématiques

Plus en détail

RN2-Programmation Orientée Objet - JAVA CH 1 Introduction à la POO et Java

RN2-Programmation Orientée Objet - JAVA CH 1 Introduction à la POO et Java RN2-Programmation Orientée Objet - JAVA CH 1 à la POO et Java Licence Professionnelle 2006 Agnès Guerraz INRIA Rhône-Alpes agnes.guerraz@inria.fr LP UPMF, Grenoble Septembre 2006 Ce cours reprend en grande

Plus en détail

Le langage C++ est un langage de programmation puissant, polyvalent, on serait presque tenté de dire universel, massivement utilisé dans l'industrie

Le langage C++ est un langage de programmation puissant, polyvalent, on serait presque tenté de dire universel, massivement utilisé dans l'industrie Chapitre I : Les bases du C++ Le langage C++ est un langage de programmation puissant, polyvalent, on serait presque tenté de dire universel, massivement utilisé dans l'industrie du logiciel, et ce depuis

Plus en détail

Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation 24 octobre 2007impérative 1 / 44 et. structures de données simples

Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation 24 octobre 2007impérative 1 / 44 et. structures de données simples Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation impérative et structures de données simples Introduction au langage C Sandrine Blazy - 1ère année 24 octobre 2007 Cours d Algorithmique-Programmation

Plus en détail

Projet de Veille Technologique

Projet de Veille Technologique Projet de Veille Technologique Programmation carte à puce - JavaCard Ing. MZOUGHI Ines (i.mzoughi@gmail.com) Dr. MAHMOUDI Ramzi (mahmoudr@esiee.fr) TEST Sommaire Programmation JavaCard Les prérequis...

Plus en détail

TP 1. Prise en main du langage Python

TP 1. Prise en main du langage Python TP. Prise en main du langage Python Cette année nous travaillerons avec le langage Python version 3. ; nous utiliserons l environnement de développement IDLE. Étape 0. Dans votre espace personnel, créer

Plus en détail

java : Langage et Environnement

java : Langage et Environnement java : Langage et Environnement 1. rintroduction ava est une nouvelle technologie conçue par Sun Microsystems l'un des premiers fabriquants des stations de travail Sun. Depuis son apparition, à peine plus

Plus en détail

Java c est quoi? Java. Java. Java : Principe de fonctionnement 31/01/2012. 1 - Vue générale 2 - Mon premier programme 3 - Types de Programme Java

Java c est quoi? Java. Java. Java : Principe de fonctionnement 31/01/2012. 1 - Vue générale 2 - Mon premier programme 3 - Types de Programme Java 1 - Vue générale 2 - Mon premier programme 3 - Types de Programme 1 2 c est quoi? Technologie développée par SUN Microsystems lancée en 1995 Dans un des premiers papiers* sur le langage JAVA, SUN le décrit

Plus en détail

TP1. Outils Java Eléments de correction

TP1. Outils Java Eléments de correction c sep. 2008, v2.1 Java TP1. Outils Java Eléments de correction Sébastien Jean Le but de ce TP, sur une séance, est de se familiariser avec les outils de développement et de documentation Java fournis par

Plus en détail

Chapitre 1 I:\ Soyez courageux!

Chapitre 1 I:\ Soyez courageux! Chapitre 1 I:\ Soyez courageux! Pour ne rien vous cacher, le langage d'assembleur (souvent désigné sous le terme "Assembleur", bien que ce soit un abus de langage, puisque "Assembleur" désigne le logiciel

Plus en détail

Cours d Algorithmique et de Langage C 2005 - v 3.0

Cours d Algorithmique et de Langage C 2005 - v 3.0 Cours d Algorithmique et de Langage C 2005 - v 3.0 Bob CORDEAU cordeau@onera.fr Mesures Physiques IUT d Orsay 15 mai 2006 Avant-propos Avant-propos Ce cours en libre accès repose sur trois partis pris

Plus en détail

Algorithme. Table des matières

Algorithme. Table des matières 1 Algorithme Table des matières 1 Codage 2 1.1 Système binaire.............................. 2 1.2 La numérotation de position en base décimale............ 2 1.3 La numérotation de position en base binaire..............

Plus en détail

RMI le langage Java XII-1 JMF

RMI le langage Java XII-1 JMF Remote Method Invocation (RMI) XII-1 Introduction RMI est un ensemble de classes permettant de manipuler des objets sur des machines distantes (objets distants) de manière similaire aux objets sur la machine

Plus en détail

SHERLOCK 7. Version 1.2.0 du 01/09/09 JAVASCRIPT 1.5

SHERLOCK 7. Version 1.2.0 du 01/09/09 JAVASCRIPT 1.5 SHERLOCK 7 Version 1.2.0 du 01/09/09 JAVASCRIPT 1.5 Cette note montre comment intégrer un script Java dans une investigation Sherlock et les différents aspects de Java script. S T E M M E R I M A G I N

Plus en détail

Chapitre 10. Les interfaces Comparable et Comparator 1

Chapitre 10. Les interfaces Comparable et Comparator 1 Chapitre 10: Les interfaces Comparable et Comparator 1/5 Chapitre 10 Les interfaces Comparable et Comparator 1 1 Ce chapitre a été extrait du document "Objets, Algorithmes, Patterns" de [René Lalement],

Plus en détail

Java Licence Professionnelle CISII, 2009-2010. Cours 2 : Classes et Objets

Java Licence Professionnelle CISII, 2009-2010. Cours 2 : Classes et Objets Licence Professionnelle CISII, 2009-2010 Cours 2 : Classes et Objets 1 Classes et Objets Objectifs des LOO : - Manipuler des objets - Découper les programmes suivant les types des objets manipulés - Regrouper

Plus en détail

DE L ALGORITHME AU PROGRAMME INTRO AU LANGAGE C 51

DE L ALGORITHME AU PROGRAMME INTRO AU LANGAGE C 51 DE L ALGORITHME AU PROGRAMME INTRO AU LANGAGE C 51 PLAN DU COURS Introduction au langage C Notions de compilation Variables, types, constantes, tableaux, opérateurs Entrées sorties de base Structures de

Plus en détail

Programme «Analyste Programmeur» Diplôme d état : «Développeur Informatique» Homologué au niveau III (Bac+2) (JO N 176 du 1 août 2003) (34 semaines)

Programme «Analyste Programmeur» Diplôme d état : «Développeur Informatique» Homologué au niveau III (Bac+2) (JO N 176 du 1 août 2003) (34 semaines) Programme «Analyste Programmeur» Diplôme d état : «Développeur Informatique» Homologué au niveau III (Bac+2) (JO N 176 du 1 août 2003) (34 semaines) Module 1 : Programmer une application informatique Durée

Plus en détail

Architecture de l ordinateur

Architecture de l ordinateur Architecture de l ordinateur Emmanuel Lazard Université Paris-Dauphine mars 2011 Computers are my forte! BRAZIL (Terry Gilliam, 1985) Ce document a initialement été publié sous forme de livre : Emmanuel

Plus en détail

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3. 1. Structure d un programme C Un programme est un ensemble de fonctions. La fonction "main" constitue le point d entrée pour l exécution. Un exemple simple : #include int main() { printf ( this

Plus en détail

PROGRAMMATION PAR OBJETS

PROGRAMMATION PAR OBJETS PROGRAMMATION PAR OBJETS Java Environnement et constructions spécifiques Walter Rudametkin Maître de Conférences Bureau F011 Walter.Rudametkin@polytech-lille.fr B. Carré Polytech Lille 2 Java (Sun 1995)

Plus en détail

Représentation d un entier en base b

Représentation d un entier en base b Représentation d un entier en base b 13 octobre 2012 1 Prérequis Les bases de la programmation en langage sont supposées avoir été travaillées L écriture en base b d un entier est ainsi défini à partir

Plus en détail

Initiation à la programmation en Python

Initiation à la programmation en Python I-Conventions Initiation à la programmation en Python Nom : Prénom : Une commande Python sera écrite en caractère gras. Exemples : print 'Bonjour' max=input("nombre maximum autorisé :") Le résultat de

Plus en détail

Arithmétique binaire. Chapitre. 5.1 Notions. 5.1.1 Bit. 5.1.2 Mot

Arithmétique binaire. Chapitre. 5.1 Notions. 5.1.1 Bit. 5.1.2 Mot Chapitre 5 Arithmétique binaire L es codes sont manipulés au quotidien sans qu on s en rende compte, et leur compréhension est quasi instinctive. Le seul fait de lire fait appel au codage alphabétique,

Plus en détail

Java pour le Web. Cours Java - F. Michel

Java pour le Web. Cours Java - F. Michel Java pour le Web Cours Java - F. Michel Introduction à JEE 6 (ex J2EE) Historique Qu'est-ce que JEE JEE : Java Entreprise Edition (ex J2EE) 1. Une technologie outils liés au langage Java + des spécifications

Plus en détail

Cours 1 : Introduction Ordinateurs - Langages de haut niveau - Application

Cours 1 : Introduction Ordinateurs - Langages de haut niveau - Application Université de Provence Licence Math-Info Première Année V. Phan Luong Algorithmique et Programmation en Python Cours 1 : Introduction Ordinateurs - Langages de haut niveau - Application 1 Ordinateur Un

Plus en détail

Plan. Exemple: Application bancaire. Introduction. OCL Object Constraint Language Le langage de contraintes d'uml

Plan. Exemple: Application bancaire. Introduction. OCL Object Constraint Language Le langage de contraintes d'uml OCL Object Constraint Language Le langage de contraintes d'uml Plan 1. Introduction 2. Les principaux concepts d'ocl Object Constraint Language 1 Object Constraint Language 2 Exemple: une application bancaire

Plus en détail

Bases Java - Eclipse / Netbeans

Bases Java - Eclipse / Netbeans Institut Galilée PDJ Année 2014-2015 Master 1 Environnements Java T.P. 1 Bases Java - Eclipse / Netbeans Il existe plusieurs environnements Java. Il est ESSENTIEL d utiliser la bonne version, et un environnement

Plus en détail

LES TYPES DE DONNÉES DU LANGAGE PASCAL

LES TYPES DE DONNÉES DU LANGAGE PASCAL LES TYPES DE DONNÉES DU LANGAGE PASCAL 75 LES TYPES DE DONNÉES DU LANGAGE PASCAL CHAPITRE 4 OBJECTIFS PRÉSENTER LES NOTIONS D ÉTIQUETTE, DE CONS- TANTE ET DE IABLE DANS LE CONTEXTE DU LAN- GAGE PASCAL.

Plus en détail

Seance 2: En respectant la méthode de programmation par contrat, implémentez les autres fonctions de jeu.

Seance 2: En respectant la méthode de programmation par contrat, implémentez les autres fonctions de jeu. Seance 2: Complétion du code de jeu. (durée max: 2h) Mot clé const et pointeurs: En respectant la méthode de programmation par contrat, implémentez les autres fonctions de jeu. Implémentez jeu_recupere_piece

Plus en détail

La mémoire. Un ordinateur. L'octet. Le bit

La mémoire. Un ordinateur. L'octet. Le bit Introduction à l informatique et à la programmation Un ordinateur Un ordinateur est une machine à calculer composée de : un processeur (ou unité centrale) qui effectue les calculs une mémoire qui conserve

Plus en détail

Traduction des Langages : Le Compilateur Micro Java

Traduction des Langages : Le Compilateur Micro Java BARABZAN Jean-René OUAHAB Karim TUCITO David 2A IMA Traduction des Langages : Le Compilateur Micro Java µ Page 1 Introduction Le but de ce projet est d écrire en JAVA un compilateur Micro-Java générant

Plus en détail

Qu'est-ce que le BPM?

Qu'est-ce que le BPM? Qu'est-ce que le BPM? Le BPM (Business Process Management) n'est pas seulement une technologie mais, dans les grandes lignes, une discipline de gestion d'entreprise qui s'occupe des procédures contribuant

Plus en détail

Informatique / Programmation

Informatique / Programmation Java / Introduction Caractéristiques principales Informatique / Programmation Orientation Objet (C++) -- Sécurité intégrée Portabilité Programmation orientée objet avec Java 01 : Introduction / Éléments

Plus en détail

Rappel. Analyse de Données Structurées - Cours 12. Un langage avec des déclaration locales. Exemple d'un programme

Rappel. Analyse de Données Structurées - Cours 12. Un langage avec des déclaration locales. Exemple d'un programme Rappel Ralf Treinen Université Paris Diderot UFR Informatique Laboratoire Preuves, Programmes et Systèmes treinen@pps.univ-paris-diderot.fr 6 mai 2015 Jusqu'à maintenant : un petit langage de programmation

Plus en détail