{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "title: Collections en Java\n",
    "description: Compréhension et utilisation des collections\n",
    "notebook-links: false\n",
    "categories:\n",
    "  - Java\n",
    "  - I111\n",
    "  - PO43\n",
    "  - Lecture\n",
    "provide_notes: true\n",
    "provide_slides: true\n",
    "jupyter: java\n",
    "---\n",
    "\n",
    "## L’intérêt des collections\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Importance des structures de données** :\n",
    "  - Choisir des structures de données adaptées est crucial lors du développement.\n",
    "  - Permet de stocker, parcourir et retrouver des objets efficacement.\n",
    "- **Types de structures de données** :\n",
    "  - Tableaux, listes, arbres, tables de hachage, etc.\n",
    "- **Ressources supplémentaires** :\n",
    "  - Un [tutoriel](https://docs.oracle.com/javase/tutorial/collections/index.html)\n",
    "  - La [javadoc](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/package-summary.html#CollectionsFramework)\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "Lors d’un développement, l’un des points cruciaux est le choix de structures de données adaptées. Il est souvent nécessaire de développer des solutions pour stocker des objets, les parcourir et les retrouver, avec ou sans clé. Ces structures peuvent prendre la forme de tableaux, de listes, d’arbres, de tables de hachage, etc.\n",
    "\n",
    "### Types de structures de données\n",
    "\n",
    "- **Tableaux** : Utilisés pour stocker des éléments de même type dans un ordre séquentiel.\n",
    "- **Listes** : Permettent de stocker des éléments de manière ordonnée, avec des opérations d'insertion et de suppression flexibles.\n",
    "- **Arbres** : Structures hiérarchiques permettant des recherches rapides et des opérations de tri.\n",
    "- **Tables de hachage** : Utilisées pour stocker des paires clé-valeur, permettant des recherches rapides basées sur des clés.\n",
    "\n",
    "### Ressources supplémentaires\n",
    "\n",
    "Pour en savoir plus, vous pouvez consulter :\n",
    "- Un [tutoriel](https://docs.oracle.com/javase/tutorial/collections/index.html)\n",
    "- La [javadoc](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/package-summary.html#CollectionsFramework)\n",
    ":::\n",
    "\n",
    "## Les collections\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Définition** : En Java, une collection est un objet qui permet de contenir des références vers d’autres objets.\n",
    "- **Comparaison avec les tableaux** :\n",
    "  - Les tableaux sont une structure de données qui contient des références.\n",
    "  - Les collections offrent plus de flexibilité et de fonctionnalités.\n",
    "- **Le JDK propose** :\n",
    "  - **Interfaces** : Définissent les grands types de collections (List, Set, Map, etc.).\n",
    "  - **Classes abstraites** : Implantent partiellement ces interfaces (AbstractList, AbstractSet, etc.).\n",
    "  - **Classes concrètes** : Précisent les implantations (ArrayList, HashSet, HashMap, etc.).\n",
    "  - **Paquetage `java.util`** : Contient toutes les interfaces et classes de collections.\n",
    "  - **Itérateurs** : Mécanisme de parcours général des collections.\n",
    "  - **Outils de tri et de recherche** : Méthodes utilitaires pour trier et rechercher dans les collections.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "En Java, une collection est un objet qui permet de contenir des références vers d’autres objets. Nous avons déjà vu une structure qui contient des références : les tableaux. Cependant, les collections offrent plus de flexibilité et de fonctionnalités.\n",
    "\n",
    "Le JDK propose plusieurs éléments pour travailler avec les collections :\n",
    "\n",
    "- **Interfaces** : Elles définissent les grands types de collections, comme List, Set, et Map.\n",
    "- **Classes abstraites** : Elles implantent partiellement ces interfaces, fournissant une base pour les classes concrètes.\n",
    "- **Classes concrètes** : Elles précisent les implantations des interfaces et des classes abstraites, comme ArrayList, HashSet, et HashMap.\n",
    "- **Paquetage `java.util`** : Toutes les interfaces et classes de collections sont définies dans ce paquetage.\n",
    "- **Itérateurs** : Un mécanisme de parcours général est proposé via les itérateurs, permettant de parcourir les éléments d'une collection de manière uniforme.\n",
    "- **Outils de tri et de recherche** : Le JDK fournit également des méthodes utilitaires pour trier et rechercher dans les collections, facilitant ainsi la manipulation des données.\n",
    "\n",
    "Ces éléments permettent de créer des structures de données flexibles et efficaces pour stocker, parcourir et manipuler des objets en Java.\n",
    ":::\n",
    "\n",
    "## Une hiérarchie d’Interfaces\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "En Java, les collections se distinguent en plusieurs types principaux :\n",
    "\n",
    "- **Collections** ([Collection](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Collection.html))\n",
    "  - **Ensembles** ([Set](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Set.html))\n",
    "    - **Ensembles triés** ([SortedSet](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/SortedSet.html))\n",
    "  - **Listes** ([List](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/List.html))\n",
    "  - **Files** ([Queue](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Queue.html))\n",
    "- **Dictionnaires** ([Map](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Map.html))\n",
    "  - **Maps triées** ([SortedMap](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/SortedMap.html))\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "En Java, les collections sont organisées en une hiérarchie d'interfaces qui permettent de structurer et de manipuler des groupes d'objets de manière efficace. La principale interface est `Collection`, qui se décline en plusieurs sous-types spécialisés :\n",
    "\n",
    "- **Set** : Représente des ensembles d'éléments uniques.\n",
    "- **SortedSet** : Maintient les éléments dans un ordre spécifique.\n",
    "- **List** : Permet de gérer des séquences ordonnées d'éléments.\n",
    "- **Queue** : Facilite la gestion des files d'attente.\n",
    "- **Map** : Utilisée pour associer des clés à des valeurs.\n",
    "- **SortedMap** : Maintient les paires clé-valeur dans un ordre déterminé.\n",
    "\n",
    "Toutes ces interfaces et leurs implémentations sont définies dans le paquetage `java.util`, offrant ainsi un cadre robuste et flexible pour le développement d'applications Java.\n",
    ":::\n",
    "\n",
    "## Des classes abstraites\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Classes abstraites** : Un ensemble de classes abstraites implémente les interfaces des collections et prend en charge les parties communes.\n",
    "  - **Exemples** :\n",
    "    - `AbstractCollection`, `AbstractList`, `AbstractQueue`, `AbstractSequentialList`, `AbstractSet`, `AbstractMap`\n",
    "- **Classes concrètes** : Ces classes abstraites sont réalisées par des classes concrètes qui implémentent les fonctionnalités spécifiques.\n",
    "  - **Exemples** :\n",
    "    - [ArrayList](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/ArrayList.html)\n",
    "      - **Algorithme** : Basée sur un tableau dynamique.\n",
    "      - **Complexité** :\n",
    "        - Accès par index : Θ(1)\n",
    "        - Insertion/Suppression (à la fin) : Θ(1)\n",
    "        - Insertion/Suppression (au milieu) : Θ(n)\n",
    "    - [TreeSet](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/TreeSet.html)\n",
    "      - **Algorithme** : Basée sur un arbre rouge-noir.\n",
    "      - **Complexité** :\n",
    "        - Insertion : Θ(log n)\n",
    "        - Suppression : Θ(log n)\n",
    "        - Recherche : Θ(log n)\n",
    "    - [HashMap](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/HashMap.html)\n",
    "      - **Algorithme** : Basée sur une table de hachage.\n",
    "      - **Complexité** :\n",
    "        - Insertion : Θ(1) en moyenne\n",
    "        - Suppression : Θ(1) en moyenne\n",
    "        - Recherche : Θ(1) en moyenne\n",
    "    - [TreeMap](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/TreeMap.html)\n",
    "      - **Algorithme** : Basée sur un arbre rouge-noir.\n",
    "      - **Complexité** :\n",
    "        - Insertion : Θ(log n)\n",
    "        - Suppression : Θ(log n)\n",
    "        - Recherche : Θ(log n)\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "En Java, un ensemble de classes abstraites implémente les interfaces des collections, en prenant en charge les parties communes de leur fonctionnement. Parmi ces classes abstraites, on trouve :\n",
    "\n",
    "- `AbstractCollection`\n",
    "- `AbstractList`\n",
    "- `AbstractQueue`\n",
    "- `AbstractSequentialList`\n",
    "- `AbstractSet`\n",
    "- `AbstractMap`\n",
    "\n",
    "Ces classes fournissent une base solide pour les collections en définissant des comportements génériques, ce qui permet de réduire la duplication de code. Les classes concrètes, telles que `ArrayList`, `TreeSet`, `HashMap` et `TreeMap`, héritent de ces classes abstraites et implémentent les fonctionnalités spécifiques nécessaires pour chaque type de collection. Cela permet une grande flexibilité et réutilisabilité du code, tout en assurant une cohérence dans le comportement des différentes collections.\n",
    ":::\n",
    "\n",
    "### Hierarchie"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"us-ascii\" standalone=\"no\"?><svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" contentStyleType=\"text/css\" height=\"341px\" preserveAspectRatio=\"none\" style=\"width:441px;height:341px;background:#000000;\" version=\"1.1\" viewBox=\"0 0 441 341\" width=\"441px\" zoomAndPan=\"magnify\"><defs/><g><rect fill=\"#1D1B1A\" height=\"1\" style=\"stroke:#1D1B1A;stroke-width:1.0;\" width=\"1\" x=\"0\" y=\"0\"/><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"12\" font-style=\"italic\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"129\" x=\"5\" y=\"17\">PlantUML 1.2024.1</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"12\" font-style=\"italic\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"4\" x=\"5\" y=\"30.9688\">&#160;</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"12\" font-style=\"italic\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"419\" x=\"5\" y=\"44.9375\">&lt;b&gt;This version of PlantUML is 595 days old, so you should</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"12\" font-style=\"italic\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"427\" x=\"5\" y=\"58.9063\">&lt;b&gt;consider upgrading from https://plantuml.com/download</text><rect fill=\"#33FF02\" height=\"21.2969\" style=\"stroke:#33FF02;stroke-width:1.0;\" width=\"265\" x=\"5\" y=\"68.875\"/><text fill=\"#000000\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"178\" x=\"6\" y=\"83.875\">[From string (line 13) ]</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"5\" x=\"5\" y=\"104.1719\">&#160;</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"79\" x=\"5\" y=\"120.4688\">@startuml</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"146\" x=\"5\" y=\"136.7656\">package java.util {</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"202\" x=\"25\" y=\"153.0625\">interface Collection&lt;E&gt; {</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"81\" x=\"45\" y=\"169.3594\">+int size()</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"153\" x=\"45\" y=\"185.6563\">+boolean isEmpty()</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"225\" x=\"45\" y=\"201.9531\">+boolean contains(Object o)</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"180\" x=\"45\" y=\"218.25\">+Iterator&lt;E&gt; iterator()</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"145\" x=\"45\" y=\"234.5469\">+boolean add(E e)</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"218\" x=\"45\" y=\"250.8438\">+boolean remove(Object o)</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"101\" x=\"45\" y=\"267.1406\">+void clear()</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"10\" x=\"25\" y=\"283.4375\">}</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"5\" x=\"5\" y=\"299.7344\">&#160;</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" text-decoration=\"wavy underline\" textLength=\"337\" x=\"25\" y=\"316.0313\">interface List&lt;E&gt; extends Collection&lt;E&gt; {</text><text fill=\"#FF0000\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"106\" x=\"10\" y=\"332.3281\">Syntax Error?</text><!--SRC=[hLBBRi8m4Bpp5NkaAkGB41Ag8XMb5OTMkPjaeOPWHxQ9I2d_thMRa9TfEJIdP1uxzcHpbkpP5c772XOS3S_WF09wk32eDYn1U99PXedXKip2USNQvv4aeFadZXyQR2rbXam0r-4XDwMFIgGmZ0izNgrtD1TaIxEaK6QaiacyUlVDO6aw3W4zZCA3BD0tkv0yXOH4zSJBg7VJ5wwDJSQJGP7gspU_VGmNOc5R3XSfdYP0YWmFA4nB5y8MJIFgCBhDtB9Nz_HDk6AhZQy7IsTCcwLNCYZb3V_iPE1vPVaica3yd-iIOLaVTO_bByAOPSVh0XJseoMENU_UEJ7aHpEEB4f7zpYxgzKr3vRBeRQxQ6wbzDOcMYrIIIvAzurKOX0AeygVAkaNs8zcKDLwGlzI0opMsYYMc7g7pqFDGYbMzdVy3jypqn-zBQXT5LoR6i-xGhpFqmjgLgVlwozLPMsgXDbN45pb3UvazdvTWKKSHGVgCWGuWXAx106E66QGRZeTZlvBQ9Cktm00]--></g></svg>"
      ],
      "text/plain": [
       "<?xml version=\"1.0\" encoding=\"us-ascii\" standalone=\"no\"?><svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" contentStyleType=\"text/css\" height=\"341px\" preserveAspectRatio=\"none\" style=\"width:441px;height:341px;background:#000000;\" version=\"1.1\" viewBox=\"0 0 441 341\" width=\"441px\" zoomAndPan=\"magnify\"><defs/><g><rect fill=\"#1D1B1A\" height=\"1\" style=\"stroke:#1D1B1A;stroke-width:1.0;\" width=\"1\" x=\"0\" y=\"0\"/><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"12\" font-style=\"italic\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"129\" x=\"5\" y=\"17\">PlantUML 1.2024.1</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"12\" font-style=\"italic\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"4\" x=\"5\" y=\"30.9688\">&#160;</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"12\" font-style=\"italic\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"419\" x=\"5\" y=\"44.9375\">&lt;b&gt;This version of PlantUML is 595 days old, so you should</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"12\" font-style=\"italic\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"427\" x=\"5\" y=\"58.9063\">&lt;b&gt;consider upgrading from https://plantuml.com/download</text><rect fill=\"#33FF02\" height=\"21.2969\" style=\"stroke:#33FF02;stroke-width:1.0;\" width=\"265\" x=\"5\" y=\"68.875\"/><text fill=\"#000000\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"178\" x=\"6\" y=\"83.875\">[From string (line 13) ]</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"5\" x=\"5\" y=\"104.1719\">&#160;</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"79\" x=\"5\" y=\"120.4688\">@startuml</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"146\" x=\"5\" y=\"136.7656\">package java.util {</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"202\" x=\"25\" y=\"153.0625\">interface Collection&lt;E&gt; {</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"81\" x=\"45\" y=\"169.3594\">+int size()</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"153\" x=\"45\" y=\"185.6563\">+boolean isEmpty()</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"225\" x=\"45\" y=\"201.9531\">+boolean contains(Object o)</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"180\" x=\"45\" y=\"218.25\">+Iterator&lt;E&gt; iterator()</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"145\" x=\"45\" y=\"234.5469\">+boolean add(E e)</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"218\" x=\"45\" y=\"250.8438\">+boolean remove(Object o)</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"101\" x=\"45\" y=\"267.1406\">+void clear()</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"10\" x=\"25\" y=\"283.4375\">}</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"5\" x=\"5\" y=\"299.7344\">&#160;</text><text fill=\"#33FF02\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" text-decoration=\"wavy underline\" textLength=\"337\" x=\"25\" y=\"316.0313\">interface List&lt;E&gt; extends Collection&lt;E&gt; {</text><text fill=\"#FF0000\" font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bold\" lengthAdjust=\"spacing\" textLength=\"106\" x=\"10\" y=\"332.3281\">Syntax Error?</text><!--SRC=[hLBBRi8m4Bpp5NkaAkGB41Ag8XMb5OTMkPjaeOPWHxQ9I2d_thMRa9TfEJIdP1uxzcHpbkpP5c772XOS3S_WF09wk32eDYn1U99PXedXKip2USNQvv4aeFadZXyQR2rbXam0r-4XDwMFIgGmZ0izNgrtD1TaIxEaK6QaiacyUlVDO6aw3W4zZCA3BD0tkv0yXOH4zSJBg7VJ5wwDJSQJGP7gspU_VGmNOc5R3XSfdYP0YWmFA4nB5y8MJIFgCBhDtB9Nz_HDk6AhZQy7IsTCcwLNCYZb3V_iPE1vPVaica3yd-iIOLaVTO_bByAOPSVh0XJseoMENU_UEJ7aHpEEB4f7zpYxgzKr3vRBeRQxQ6wbzDOcMYrIIIvAzurKOX0AeygVAkaNs8zcKDLwGlzI0opMsYYMc7g7pqFDGYbMzdVy3jypqn-zBQXT5LoR6i-xGhpFqmjgLgVlwozLPMsgXDbN45pb3UvazdvTWKKSHGVgCWGuWXAx106E66QGRZeTZlvBQ9Cktm00]--></g></svg>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "//| echo: false\n",
    "//| output: true\n",
    "String script=\"\"\"\n",
    "@startuml\n",
    "package java.util {\n",
    "    interface Collection<E> {\n",
    "        +int size()\n",
    "        +boolean isEmpty()\n",
    "        +boolean contains(Object o)\n",
    "        +Iterator<E> iterator()\n",
    "        +boolean add(E e)\n",
    "        +boolean remove(Object o)\n",
    "        +void clear()\n",
    "    }\n",
    "\n",
    "    interface List<E> extends Collection<E> {\n",
    "        +boolean add(E e)\n",
    "        +void add(int index, E element)\n",
    "        +E get(int index)\n",
    "        +E set(int index, E element)\n",
    "        +E remove(int index)\n",
    "        +int indexOf(Object o)\n",
    "        +int lastIndexOf(Object o)\n",
    "    }\n",
    "\n",
    "    interface Set<E> extends Collection<E> {\n",
    "    }\n",
    "\n",
    "    interface Map<K, V> {\n",
    "        +int size()\n",
    "        +boolean isEmpty()\n",
    "        +boolean containsKey(Object key)\n",
    "        +boolean containsValue(Object value)\n",
    "        +V get(Object key)\n",
    "        +V put(K key, V value)\n",
    "        +V remove(Object key)\n",
    "        +void clear()\n",
    "        +Set<K> keySet()\n",
    "        +Collection<V> values()\n",
    "        +Set<Map.Entry<K, V>> entrySet()\n",
    "    }\n",
    "\n",
    "    class  AbstractList<E> {\n",
    "    }\n",
    "    \n",
    "    class ArrayList<E> extends AbstractList<E> {\n",
    "    }\n",
    "\n",
    "    class HashSet<E> extends AbstractSet<E> {\n",
    "    }\n",
    "    class TreeSet<E> extends AbstractSet<E> {\n",
    "    }\n",
    "\n",
    "    class HashMap<K, V> extends AbstractMap<K, V> {\n",
    "    }\n",
    "\n",
    "    Collection <|.. AbstractCollection\n",
    "    List <|.. AbstractList\n",
    "    Set <|.. AbstractSet\n",
    "    Map <|.. AbstractMap\n",
    "    AbstractCollection <|-- AbstractList\n",
    "    AbstractCollection <|-- AbstractSet\n",
    "}\n",
    "@enduml\n",
    "\n",
    "\"\"\";\n",
    "    \n",
    "IJava.getKernelInstance().getMagics().applyCellMagic(\"plantUML\",List.of(),script);  \n",
    "return null;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Structures de Données Classiques\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Hiérarchie de classes** : Organisation des structures de données en classes et interfaces.\n",
    "- **Interfaces communes** : Flexibilité et réutilisabilité accrues.\n",
    "- **Efficacité** : Stockage, parcours et manipulation optimisés des collections d'objets.\n",
    "- Interface `List`\n",
    "  - **Tableaux de taille variable** : `ArrayList`\n",
    "    - Héritent de `java.util.AbstractList` et `AbstractCollection`\n",
    "    - Implémentent les interfaces `Collection` et `List`\n",
    "  - **Listes chaînées** : `LinkedList`\n",
    "- Interface `Set`\n",
    "  - **Tables de hachage** : `HashSet`\n",
    "  - **Arbres à balance équilibrée** : `TreeSet`\n",
    "- Interface `Map`\n",
    "  - **Tables de hachage** : `HashMap`\n",
    "  - **Arbres à balance équilibrée** : `TreeMap`\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "En Java, les structures de données classiques sont organisées dans une hiérarchie de classes et implémentent des interfaces communes, offrant ainsi une grande flexibilité et réutilisabilité du code. Parmi les interfaces principales, on trouve `List`, `Set` et `Map`. Les `List` incluent des implémentations comme `ArrayList`, qui hérite de `AbstractList` et `AbstractCollection`, et `LinkedList`, qui permet de gérer des listes chaînées. Les `Set` comprennent des structures comme `HashSet` pour les tables de hachage et `TreeSet` pour les arbres à balance équilibrée. Enfin, les `Map` incluent `HashMap` et `TreeMap`, qui permettent de gérer des associations clé-valeur avec des tables de hachage et des arbres équilibrés, respectivement. Ces structures permettent de stocker, parcourir et manipuler des collections d'objets de manière efficace et optimisée.\n",
    ":::\n",
    "\n",
    "## Un premier exemple\n",
    "\n",
    "Le programme suivant ajoute trois chaînes de caractères (“Medor”, “Rex” et “Brutus”) à la liste maListe et l'affiche. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Medor, Rex, Brutus]\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "import java.util.*; // Importation de toutes les classes du paquetage java.util\n",
    "List maListe = new ArrayList(); // Création d'une nouvelle liste de type ArrayList\n",
    "maListe.add(\"Medor\"); // Ajout de l'élément \"Medor\" à la liste\n",
    "maListe.add(\"Rex\"); // Ajout de l'élément \"Rex\" à la liste\n",
    "maListe.add(\"Brutus\"); // Ajout de l'élément \"Brutus\" à la liste\n",
    "\n",
    "System.out.println(maListe); // Affichage du contenu de la liste"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Administration des collections\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Tri, recherche, min, max** : Méthodes statiques pour gérer les collections.\n",
    "- **Classe `Collections`** :\n",
    "  - Algorithmes polymorphes pour manipuler les collections.\n",
    "  - Wrappers pour créer de nouvelles collections basées sur des collections existantes.\n",
    "  - **Exemple** : `Collections.sort(maListe);` pour trier une liste.\n",
    "- **Classe `Arrays`** :\n",
    "  - Méthodes pour manipuler les tableaux (tri, recherche).\n",
    "  - Fabrique statique pour voir les tableaux comme des listes.\n",
    "  - **Exemple** : `Arrays.sort(monTableau);` pour trier un tableau.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "L'administration des collections en Java, telles que le tri, la recherche, et la détermination des valeurs minimales et maximales, est assurée par des méthodes statiques des classes suivantes :\n",
    "\n",
    "- **[Collections](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Collections.html)** :\n",
    "  - Cette classe fournit des méthodes pour opérer sur ou retourner des collections.\n",
    "  - Elle inclut des algorithmes polymorphes pour manipuler les collections, tels que le tri (`sort`), la recherche (`binarySearch`), et la détermination des valeurs minimales et maximales (`min`, `max`).\n",
    "  - Elle propose également des \"wrappers\" qui retournent une nouvelle collection basée sur une collection spécifiée, comme `unmodifiableList`, `synchronizedList`, etc.\n",
    ":::\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Liste triée : [Brutus, Medor, Rex]\n",
      "Min : Brutus\n",
      "Max : Rex\n"
     ]
    }
   ],
   "source": [
    "\n",
    "Collections.sort(maListe);\n",
    "System.out.println(\"Liste triée : \" + maListe);\n",
    "System.out.println(\"Min : \" + Collections.min(maListe));\n",
    "System.out.println(\"Max : \" + Collections.max(maListe));\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Classe `Arrays`** :\n",
    "  - Méthodes pour manipuler les tableaux (tri, recherche).\n",
    "  - Fabrique statique pour voir les tableaux comme des listes.\n",
    "  - **Exemple** : `Arrays.sort(monTableau);` pour trier un tableau.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "- **[Arrays](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Arrays.html)** :\n",
    "  - Cette classe contient diverses méthodes pour manipuler les tableaux, comme le tri (`sort`) et la recherche (`binarySearch`).\n",
    "  - Elle inclut également une fabrique statique (`asList`) qui permet de voir les tableaux comme des listes, facilitant ainsi leur manipulation avec les méthodes des collections.\n",
    ":::\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tableau trié : [Brutus, Medor, Rex]\n"
     ]
    }
   ],
   "source": [
    "String[] monTableau = {\"Medor\", \"Rex\", \"Brutus\"};\n",
    "Arrays.sort(monTableau);\n",
    "System.out.println(\"Tableau trié : \" + Arrays.toString(monTableau));\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## Les standards et les exceptions\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Constructeurs sans paramètres et avec Collection** : Disponibles pour la plupart des classes de collections.\n",
    "- **Factories** : Disponibles via `Arrays` et des méthodes statiques des interfaces (depuis Java 9).\n",
    "- **Garantie limitée** : Les interfaces ne peuvent pas garantir la présence de constructeurs.\n",
    "- **Conversions facilitées** : Simplifient les conversions entre différentes implémentations de collections.\n",
    "- **Implantation complète** : Toutes les méthodes de l'interface doivent être implémentées.\n",
    "- **Méthodes non pertinentes** : Certaines méthodes n'ont pas de sens pour certaines spécialisations.\n",
    "  - **Exemple** : Collections en lecture seule (méthodes `add()`, `put()`, etc.) retournent une exception `UnsupportedOperationException`.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "En Java, la plupart des classes de collections offrent des constructeurs sans paramètres ainsi que des constructeurs prenant une collection en paramètre, facilitant ainsi l'initialisation et la conversion entre différentes implémentations de collections. Depuis Java 9, des factories sont également disponibles via la classe `Arrays` et des méthodes statiques des interfaces, permettant de créer facilement des collections. Cependant, les interfaces ne peuvent pas garantir la présence de constructeurs, car elles ne peuvent pas en définir. Toutes les méthodes définies par une interface doivent être implémentées par les classes concrètes, même si certaines méthodes peuvent ne pas avoir de sens pour certaines spécialisations. Par exemple, les collections en lecture seule ne peuvent pas implémenter les méthodes `add()` ou `put()`, et retournent donc une exception `UnsupportedOperationException` lorsqu'elles sont appelées.\n",
    ":::\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "List: [Pierre, Paul, Paul]\n",
      "Set: [Denise, Marie, Victoire]\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "// Création d'une liste à partir d'un tableau\n",
    "List list1 = Arrays.asList(\"Pierre\", \"Paul\",\"Paul\");\n",
    "// Création d'un ensemble immuable\n",
    "Set set1 = Set.of(\"Marie\",\"Denise\",\"Victoire\");\n",
    "\n",
    "// Affichage des collections\n",
    "System.out.println(\"List: \"+list1);\n",
    "System.out.println(\"Set: \"+set1);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Des collections \"génériques\" ?\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "  * Les collections représentent des ensembles d’objets (cf. type de retour de l’interface).\n",
    "  * Un objet ou un ensemble d’objets extraits sont donc du type Object.\n",
    "  * La conséquence est donc que les objets extraits doivent être transtypés.\n",
    "  * De plus les fonctions prennent en paramètres des instances de Object, il est donc difficile de contrôler la consistance.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "Les collections en Java représentent des ensembles d'objets, ce qui signifie que le type de retour des méthodes de l'interface est généralement `Object`. En conséquence, les objets extraits d'une collection doivent être transtypés pour être utilisés dans leur type spécifique. De plus, les fonctions qui manipulent ces collections prennent souvent des instances de `Object` en paramètre, ce qui complique le contrôle de la consistance des types. Cette approche peut entraîner des erreurs de type à l'exécution et rendre le code plus difficile à maintenir.\n",
    ":::\n",
    "\n",
    "## Un exemple de transtypage 1/2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "// Classe abstraite représentant un animal\n",
    "public abstract class Animal { \n",
    "    // Méthode abstraite que chaque animal doit implémenter pour définir son cri\n",
    "    public abstract String crier(); \n",
    "}\n",
    "\n",
    "public class Chien extends Animal {\n",
    "    // Implémentation de la méthode crier pour les chiens\n",
    "    @Override\n",
    "    public String crier() {\n",
    "        return System.identityHashCode(this) + \" aboie.\";\n",
    "    }\n",
    "\n",
    "    // Méthode spécifique aux chiens\n",
    "    public void sePromenerEnLaisse() {\n",
    "        // Logique pour promener le chien en laisse\n",
    "    }\n",
    "}\n",
    "\n",
    "public class Chat extends Animal {\n",
    "    // Implémentation de la méthode crier pour les chats\n",
    "    @Override\n",
    "    public String crier() {\n",
    "        return System.identityHashCode(this) + \" miaule.\";\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Un exemple de transtypage 2/2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Taille de la liste: 3\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "import java.util.*;\n",
    "List l = new ArrayList();\n",
    "l.add(new Chien());\n",
    "l.add(new Chien());\n",
    "l.add(new Chat());\n",
    "System.out.println(\"Taille de la liste: \"+l.size());"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "ename": "CompilationException",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "|   //| echo: true",
      "|   //| output: true",
      "|   //| error: true",
      "|   //| warning: true",
      "|   l.get(0).crier();",
      "using incubating module(s): jdk.incubator.vector",
      "",
      "|   l.get(0).crier();",
      "cannot find symbol",
      "  symbol:   method crier()",
      ""
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "//| error: true\n",
    "//| warning: true\n",
    "l.get(0).crier();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [],
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\u001b[36m((Animal)l.get(2)).crier();\u001b[0m: 1548039530 miaule."
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "((Animal)l.get(2)).crier();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "ename": "EvalException",
     "evalue": "class REPL.$JShell$47$Chat cannot be cast to class REPL.$JShell$46$Chien (REPL.$JShell$47$Chat and REPL.$JShell$46$Chien are in unnamed module of loader jdk.jshell.execution.DefaultLoaderDelegate$RemoteClassLoader @696da30b)",
     "output_type": "error",
     "traceback": [
      "---------------------------------------------------------------------------",
      "java.lang.ClassCastException: class REPL.$JShell$47$Chat cannot be cast to class REPL.$JShell$46$Chien (REPL.$JShell$47$Chat and REPL.$JShell$46$Chien are in unnamed module of loader jdk.jshell.execution.DefaultLoaderDelegate$RemoteClassLoader @696da30b)",
      "\tat .(#55:5)"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "//| error: true\n",
    "//| warning: true\n",
    "((Chien)l.get(2)).sePromenerEnLaisse();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Les types génériques (1/2)\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Définition** : Un type générique (ou type paramétré) permet de définir des classes, interfaces et méthodes avec des types variables.\n",
    "- **Avantages** :\n",
    "  - Réutilisabilité du code\n",
    "  - Sécurité de type à la compilation\n",
    "  - Élimination des conversions explicites\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "Un type générique (ou type paramétré) permet de définir des classes, interfaces et méthodes avec des types variables. Cela signifie que vous pouvez créer des structures de données et des algorithmes qui fonctionnent avec n’importe quel type de données, sans avoir à spécifier le type exact à l’avance.\n",
    "\n",
    "Les avantages des types génériques sont nombreux. Tout d’abord, ils permettent une réutilisabilité du code. En utilisant des types génériques, vous pouvez écrire des méthodes et des classes qui fonctionnent avec différents types de données, ce qui réduit la duplication de code et facilite la maintenance.\n",
    "\n",
    "Ensuite, les types génériques offrent une sécurité de type à la compilation. Cela signifie que les erreurs de type sont détectées lors de la compilation plutôt qu’à l’exécution, ce qui rend le code plus fiable et réduit les bugs.\n",
    "\n",
    "Enfin, les types génériques éliminent les conversions explicites. Sans types génériques, vous devez souvent convertir des types de données, ce qui peut être source d’erreurs et de complexité. Avec les types génériques, ces conversions sont implicites et gérées par le compilateur, ce qui simplifie le code et améliore sa lisibilité.\n",
    ":::\n",
    "\n",
    "## Les types génériques (2/2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\u001b[36mc.getFirst().crier();\u001b[0m: 746927499 aboie."
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "public class Couple<T1, T2> {\n",
    "    private final T1 e1;\n",
    "    private final T2 e2;\n",
    "\n",
    "    public Couple(T1 p1, T2 p2) {\n",
    "        this.e1 = p1;\n",
    "        this.e2 = p2;\n",
    "    }\n",
    "\n",
    "    public T1 getFirst() {\n",
    "        return e1;\n",
    "    }\n",
    "\n",
    "    public T2 getSecond() {\n",
    "        return e2;\n",
    "    }\n",
    "}\n",
    "\n",
    "// Exemple d'utilisation\n",
    "Couple<Chien, Chat> c = new Couple<>(new Chien(), new Chat());\n",
    "\n",
    "c.getFirst().crier();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Les types bornés (bounded types)\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Définition** : Les types bornés permettent de restreindre les types génériques à des sous-types spécifiques.\n",
    "- **Syntaxe** : `<T extends SuperType>`\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"} \n",
    "\n",
    "Les types bornés permettent de restreindre les types génériques à des sous-types spécifiques. Cela signifie que vous pouvez spécifier que le type générique doit être un sous-type d'une certaine classe ou implémenter une certaine interface.\n",
    "\n",
    ":::\n",
    "\n",
    "#### Syntaxe\n",
    "\n",
    "La syntaxe pour définir un type borné est `<T extends SuperType>`. Par exemple, si vous voulez créer une méthode générique qui accepte uniquement des instances de Number ou de ses sous-classes, vous pouvez utiliser la syntaxe suivante :\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "\n",
    " \n",
    "  public <T extends Number> void afficherNombre(T nombre) {\n",
    "      System.out.println(nombre);\n",
    "  }\n",
    "  \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "::: {.content-visible when-profile=\"notes\"} \n",
    "\n",
    "Si vous voulez créer une interface générique qui accepte uniquement des instances de Runnable ou de ses sous-classes, vous pouvez utiliser la syntaxe suivante :\n",
    "\n",
    ":::\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "\n",
    "\n",
    "public interface Processor<T extends Runnable> {\n",
    "   void process(T t);\n",
    "}\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "::: {.content-visible when-profile=\"notes\"} \n",
    "  - Avantages :\n",
    "    - Permet d'utiliser des méthodes spécifiques du supertype.\n",
    "    - Offre plus de flexibilité tout en maintenant la sécurité de type. \n",
    "\n",
    ":::\n",
    "\n",
    "### Les wildcards (1/2)\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Définition** : Les wildcards (`?`) permettent de travailler avec des types inconnus.\n",
    "- **Types de wildcards** :\n",
    "  - `? extends T` : Borne supérieure\n",
    "  - `? super T` : Borne inférieure\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "Les wildcards (`?`) permettent de travailler avec des types inconnus dans les génériques. Elles sont particulièrement utiles lorsque vous travaillez avec des collections de types variés.\n",
    "\n",
    "Il existe deux types principaux de wildcards :\n",
    "- `? extends T` : Utilisé pour les bornes supérieures, ce qui signifie que le type inconnu doit être un sous-type de `T`.\n",
    "- `? super T` : Utilisé pour les bornes inférieures, ce qui signifie que le type inconnu doit être un supertype de `T`.\n",
    ":::\n",
    "\n",
    "### Les wildcards (2/2)\n",
    "\n",
    "Voici un exemple d'utilisation de wildcard avec une borne supérieure :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "public void afficherListe(List<? extends Animal> liste) {\n",
    "    for (Animal animal : liste) {\n",
    "        animal.crier();\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Et un exemple avec une borne inférieure :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "public void ajouterChat(List<? super Chat> liste) {\n",
    "    liste.add(new Chat(\"Félix\"));\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Les collections sont génériques "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1857189662 aboie.\n",
      "1663752545 aboie.\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "List<Chien> listeDeChiens = new ArrayList<>();\n",
    "listeDeChiens.add(new Chien()); \n",
    "listeDeChiens.add(new Chien());\n",
    "for(Chien chien:listeDeChiens)\n",
    "    System.out.println(chien.crier());"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "ename": "CompilationException",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "|   //| echo: true",
      "|   //| output: true",
      "|   //| error: true",
      "|   listeDeChiens.add(new Chat());",
      "using incubating module(s): jdk.incubator.vector",
      "",
      "|   listeDeChiens.add(new Chat());",
      "incompatible types: Chat cannot be converted to Chien",
      ""
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "//| error: true\n",
    "listeDeChiens.add(new Chat());"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Une liste polymorphe:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Taille de la liste d'animaux: 3\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "List<Animal> animaux = new ArrayList(listeDeChiens);\n",
    "animaux.add(new Chat());\n",
    "System.out.println(\"Taille de la liste d'animaux: \"+animaux.size());"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1857189662 aboie.\n",
      "1663752545 aboie.\n",
      "1337289646 miaule.\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "for (Animal a:animaux)\n",
    "    System.out.println(a.crier());"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Une liste d'entiers:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "La somme est 7\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "List<Integer> l = new ArrayList<>();\n",
    "l.add(3); // Utilisation de l'autoboxing\n",
    "l.add(4);\n",
    "\n",
    "int sum = l.get(0) + l.get(1);\n",
    "System.out.println(\"La somme est \" + sum);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Le parcours d’une collection (1/2)\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Boucles traditionnelles** :\n",
    "  - Les collections indexées (Listes, etc.) peuvent être parcourues avec une boucle.\n",
    "  - **Limitation** : Cette méthode n'est pas idéale pour l'évolutivité car elle supprime l'encapsulation des collections.\n",
    "- **Itérateur** :\n",
    "  - Une instance de l'interface [Iterator](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Iterator.html) permettant d'énumérer les éléments d'une collection.\n",
    "  - Toutes les collections possèdent la méthode `iterator()` qui retourne un itérateur.\n",
    "  - Les itérateurs peuvent être spécialisés en fonction des sous-classes de Collection (ex : `ListIterator`).\n",
    "- Avantages des Itérateurs\n",
    "  - **Encapsulation** :\n",
    "    - Maintient l'encapsulation des collections.\n",
    "  - **Modification** :\n",
    "    - Permet de modifier la collection en cours de parcours.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "Les boucles traditionnelles permettent de parcourir les collections indexées (comme les listes) avec une boucle. Cependant, cette méthode présente une limitation importante : elle n'est pas idéale pour l'évolutivité car elle supprime l'encapsulation des collections. En revanche, l'utilisation d'un itérateur, qui est une instance de l'interface [Iterator](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Iterator.html), permet d'énumérer les éléments d'une collection tout en maintenant l'encapsulation. Toutes les collections possèdent la méthode `iterator()` qui retourne un itérateur, et ces itérateurs peuvent être spécialisés en fonction des sous-classes de Collection, comme par exemple `ListIterator`. Les itérateurs offrent plusieurs avantages, notamment le maintien de l'encapsulation des collections et la possibilité de modifier la collection en cours de parcours.\n",
    ":::\n",
    "\n",
    "## Le parcours d’une collection - Exemple (2/2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1857189662 aboie.\n",
      "1663752545 aboie.\n",
      "1337289646 miaule.\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "for (int i=0;i<animaux.size();i++)\n",
    "  System.out.println(animaux.get(i).crier()) ;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1857189662 ABOIE.\n",
      "1663752545 ABOIE.\n",
      "1337289646 MIAULE.\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "Iterator<Animal> itAnimaux = animaux.iterator();\n",
    "while (itAnimaux.hasNext())\n",
    "  System.out.println(itAnimaux.next()\n",
    "                     .crier().toUpperCase());"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## La conversion vers un tableau\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Méthode `toArray()`** :\n",
    "  - **Attention au type de retour** : La méthode `toArray()` retourne un tableau d'objets.\n",
    "  - **Passage d'un tableau en paramètre** : Il est possible de passer un tableau en paramètre à `toArray(T[] a)`.\n",
    "  - **Pourquoi ne pas simplement transtyper le résultat ?** : Le transtypage peut entraîner des erreurs de type à l'exécution.\n",
    "  - **Taille du tableau** : Si le tableau passé en paramètre est trop petit, un nouveau tableau du même type est créé.\n",
    "  - **Collection vide** : Une collection vide retourne un tableau vide (et non `null`).\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "La méthode `toArray()` retourne un tableau d'objets, ce qui nécessite une attention particulière au type de retour. Il est possible de passer un tableau en paramètre à `toArray(T[] a)`, mais il est déconseillé de simplement transtyper le résultat car cela peut entraîner des erreurs de type à l'exécution. Si le tableau passé en paramètre est trop petit, un nouveau tableau du même type est créé. En cas de collection vide, la méthode retourne un tableau vide et non `null`.\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[REPL.$JShell$46$Chien@6eb2771e, REPL.$JShell$46$Chien@632ad961]\n",
      "1857189662 aboie.\n",
      "1663752545 aboie.\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "Object[] tObjets = listeDeChiens.toArray();\n",
    "System.out.println(Arrays.toString(tObjets));\n",
    "for (Object c:tObjets) {System.out.println(((Chien)c).crier());};"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Conversion correcte"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1857189662 aboie.\n",
      "1663752545 aboie.\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "Chien[] desChiens = new Chien[listeDeChiens.size()];\n",
    "listeDeChiens.toArray(desChiens);\n",
    "for (Chien c:desChiens) {System.out.println(c.crier());};"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Trier une collection\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "  * Les classes Collections et Arrays proposent des méthodes de classe pour traiter les collections et des tableaux.\n",
    "  * Elles permettent en particulier de trier et de rechercher dans des listes, de faire des copies, …\n",
    "  * Nous avons déjà vu que l’on pouvait trier une collection de String, en réalité pour qu’une collection puisse être triée, ses élements doivent implanter l’interface Comparable :\n",
    "    * int compareTo(T o) Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.\n",
    "  * Attention à la consistance entre Comparable() et equals().\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "Les classes `Collections` et `Arrays` proposent des méthodes de classe pour traiter les collections et les tableaux. Elles permettent en particulier de trier et de rechercher dans des listes, de faire des copies, etc. Nous avons déjà vu que l’on pouvait trier une collection de `String`. En réalité, pour qu’une collection puisse être triée, ses éléments doivent implémenter l’interface `Comparable` : \n",
    "\n",
    "```java\n",
    "int compareTo(T o)\n",
    "```\n",
    "\n",
    "Cette méthode compare cet objet avec l'objet spécifié pour l'ordre. Elle retourne un entier négatif, zéro ou un entier positif selon que cet objet est respectivement moins que, égal à, ou supérieur à l'objet spécifié. Il est important de veiller à la consistance entre `Comparable` et `equals()`.\n",
    ":::\n",
    "\n",
    "## Egalité et Comparaison\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Interface `Comparable`** :\n",
    "  - Définit l'ordre naturel des objets.\n",
    "  - Méthode : `int compareTo(T o)`\n",
    "\n",
    "- **Interface `Comparator`** :\n",
    "  - Permet des méthodes de comparaison personnalisées.\n",
    "  - Classe : `ComparateurPoidsAnimal`\n",
    "  - Méthode : `int compare(T o1, T o2)`\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "L'interface `Comparable` et sa méthode `compareTo` définissent l'ordre naturel des objets de la classe `Animal`. En complément, la classe `ComparateurPoidsAnimal` utilise l'interface `Comparator` pour trier des objets `Animal` par leur poids, offrant ainsi une méthode de comparaison personnalisée et flexible. L'utilisation de `Comparator` permet de séparer la logique de comparaison de la classe elle-même, ce qui améliore la modularité et la flexibilité du code.\n",
    ":::\n",
    "\n",
    "### Exemple"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "public class Animal implements Comparable<Animal> {\n",
    "  public final String nom ;\n",
    "  public final int age ;\n",
    "  public final int poids ;\n",
    "  public Animal(String nom) {this(nom, -1, -1);}\n",
    "  public Animal(String nom, int age, int poids)\n",
    "    {this.nom=nom; this.age=age; this.poids=poids;}  \n",
    "  public int compareTo (Animal a) {\n",
    "    return nom.compareTo(a.nom);\n",
    "  }\n",
    "  public boolean equals (Object o) {\n",
    "    if (this == o) return true;\n",
    "    if (o == null || getClass() != o.getClass()) return false;\n",
    "    Animal animal = (Animal) o;\n",
    "    //return nom.equals(animal.nom);\n",
    "    return age == animal.age && poids == animal.poids && nom.equals(animal.nom);    \n",
    "  }\n",
    "  public String toString ( ) {\n",
    "    return \"Animal(nom=\"+nom+\",age=\"+age+\",poids=\"+poids+\")\";}\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Utilisation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Animal(nom=Medor,age=2,poids=5), Animal(nom=Figaro,age=3,poids=2), Animal(nom=Brutus,age=1,poids=15)]\n",
      "[Animal(nom=Brutus,age=1,poids=15), Animal(nom=Figaro,age=3,poids=2), Animal(nom=Medor,age=2,poids=5)]\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "List<Animal> l = new ArrayList<Animal >() ;\n",
    "Animal figaro=new Animal(\"Figaro\", 3, 2 );\n",
    "//Nom, age , poids\n",
    "l.add(new Animal(\"Medor\", 2, 5 ));\n",
    "l.add(figaro);\n",
    "l.add(new Animal(\"Brutus\", 1, 15));\n",
    "System.out.println(l);\n",
    "\n",
    "Collections.sort(l); // Trier par nom\n",
    "System.out.println(l);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "public class ComparateurPoidsAnimal implements Comparator<Animal> {\n",
    "  public int compare (Animal animal1 , Animal animal2) {\n",
    "    return animal1.poids-animal2.poids;\n",
    "  }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Animal(nom=Figaro,age=3,poids=2), Animal(nom=Medor,age=2,poids=5), Animal(nom=Brutus,age=1,poids=15)]\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "// Trier par poids\n",
    "Collections.sort (l , new ComparateurPoidsAnimal());\n",
    "System.out.println(l);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Recherche dans une collection"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Animal(nom=Brutus,age=1,poids=15), Animal(nom=Figaro,age=3,poids=2), Animal(nom=Medor,age=2,poids=5)]\n",
      "Figaro position par nom: 1\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "Collections.sort(l);\n",
    "System.out.println(l);\n",
    "int positionFigaroNom=Collections.binarySearch(l,figaro);\n",
    "System.out.println(\"Figaro position par nom: \"+positionFigaroNom);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Animal(nom=Figaro,age=3,poids=2), Animal(nom=Medor,age=2,poids=5), Animal(nom=Brutus,age=1,poids=15)]\n",
      "Figaro position par poids: 0\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "Collections.sort (l , new ComparateurPoidsAnimal());\n",
    "System.out.println(l);\n",
    "int positionFigaroPoids = Collections.binarySearch(l,figaro,new ComparateurPoidsAnimal());\n",
    "System.out.println(\"Figaro position par poids: \"+positionFigaroPoids);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Utilisation des `Set` avec des arbres (`TreeSet`)\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Définition** : `TreeSet` est une implémentation de l'interface `Set` basée sur un arbre rouge-noir.\n",
    "- **Caractéristiques** :\n",
    "  - Maintient les éléments dans un ordre trié.\n",
    "  - Offre des performances logarithmiques pour les opérations de base (insertion, suppression, recherche).\n",
    "- **Avantages** :\n",
    "  - Maintien de l'ordre naturel des éléments.\n",
    "  - Recherche rapide des éléments.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "\n",
    "#### TreeSet\n",
    "\n",
    "TreeSet est une implémentation de l'interface Set basée sur un arbre rouge-noir. Cela signifie que les éléments sont maintenus dans un ordre trié, et les opérations de base (insertion, suppression, recherche) ont des performances logarithmiques (O(log n)).\n",
    "\n",
    "Avantages\n",
    "Maintien de l'ordre naturel : Les éléments sont automatiquement triés selon leur ordre naturel ou selon un comparateur spécifié.\n",
    "Recherche rapide : Les opérations de recherche sont rapides grâce à la structure de l'arbre rouge-noir.\n",
    "\n",
    ":::\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Banane, Orange, Pomme]\n"
     ]
    }
   ],
   "source": [
    "\n",
    "Set<String> treeSet = new TreeSet<>();\n",
    "treeSet.add(\"Banane\");\n",
    "treeSet.add(\"Pomme\");\n",
    "treeSet.add(\"Orange\");\n",
    "System.out.println(treeSet); // Affiche les éléments triés\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "## Utilisation des Set avec des tables de hachage (HashSet)\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Définition** : HashSet est une implémentation de l'interface Set basée sur une table de hachage.\n",
    "- **Caractéristiques** :\n",
    "  - Ne maintient pas l'ordre des éléments.\n",
    "  - Offre des performances moyennes constantes pour les opérations de base (insertion, suppression, recherche).\n",
    "- **Avantages** :\n",
    "  - Performances rapides pour les opérations de base.\n",
    "  - Idéal pour les ensembles où l'ordre n'est pas important.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "### HashSet\n",
    "\n",
    "HashSet est une implémentation de l'interface Set basée sur une table de hachage. Contrairement à TreeSet, HashSet ne maintient pas l'ordre des éléments, mais offre des performances moyennes constantes (O(1)) pour les opérations de base (insertion, suppression, recherche).\n",
    "\n",
    "#### Avantages\n",
    "\n",
    "- **Performances rapides** : Les opérations de base sont très rapides grâce à la table de hachage.\n",
    "- **Utilisation efficace de la mémoire** : Idéal pour les ensembles où l'ordre des éléments n'est pas important.\n",
    ":::\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Set<String> hashSet = new HashSet<>();\n",
    "hashSet.add(\"Banane\"); \n",
    "hashSet.add(\"Pomme\");\n",
    "hashSet.add(\"Orange\");\n",
    "System.out.println(hashSet); // Affiche les éléments sans ordre particulier\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## Redéfinition de hashCode() et equals()\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Importance** : Pour utiliser une classe dans une table de hachage (HashSet, HashMap)\n",
    "- **Règles** :\n",
    "  - Si deux objets sont égaux selon equals(), ils doivent avoir le même hashCode\n",
    "  - Si deux objets ont le même hashCode, ils ne sont pas nécessairement égaux\n",
    "  - hashCode() doit retourner la même valeur pour le même objet\n",
    "\n",
    ":::\n",
    "\n",
    "## Redéfinition de hashCode() et equals()\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "La redéfinition correcte de `hashCode()` et `equals()` est essentielle pour utiliser une classe dans une collection basée sur une table de hachage comme `HashSet` ou `HashMap`.\n",
    "\n",
    "### Règles importantes\n",
    "- Si deux objets sont égaux selon `equals()`, ils doivent avoir le même `hashCode`\n",
    "- Si deux objets ont le même `hashCode`, ils ne sont pas nécessairement égaux \n",
    "- `hashCode()` doit retourner la même valeur pour le même objet pendant toute son existence dans une même exécution\n",
    "\n",
    "### Bonnes pratiques\n",
    "- Utiliser `Objects.hash()` pour calculer le hashCode\n",
    "- Inclure les mêmes champs dans `equals()` et `hashCode()`\n",
    "- Toujours redéfinir les deux méthodes ensemble \n",
    ":::\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "\n",
    "  public class Personne {\n",
    "      private String nom;\n",
    "      private int age;\n",
    "      public Personne(String nom, int age) {\n",
    "          this.nom = nom;\n",
    "          this.age = age;\n",
    "      } \n",
    "      @Override\n",
    "      public boolean equals(Object o) {\n",
    "          if (this == o) return true;\n",
    "          if (o == null || getClass() != o.getClass()) return false;\n",
    "          Personne personne = (Personne) o;\n",
    "          return age == personne.age && \n",
    "                 Objects.equals(nom, personne.nom);\n",
    "      }\n",
    "      \n",
    "      @Override\n",
    "      public int hashCode() {\n",
    "          return Objects.hash(nom, age);\n",
    "      }\n",
    "\n",
    "      public String toString() {\n",
    "          return \"Personne(nom=\"+nom+\",age=\"+age+\")\";\n",
    "      }\n",
    "  }\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Personne(nom=Alice,age=30), Personne(nom=Bob,age=40)]\n"
     ]
    }
   ],
   "source": [
    "import java.util.HashSet;\n",
    "Set<Personne> personnes = new HashSet<>();\n",
    "personnes.add(new Personne(\"Bob\", 40));\n",
    "personnes.add(new Personne(\"Alice\", 30));\n",
    "System.out.println(personnes);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "## L’utilisation des Maps\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- Une `Map` associe une clé unique à une valeur spécifique.\n",
    "- Chaque clé est unique (`equals()` retourne `false` pour deux clés différentes).\n",
    "- Pour les tables de hachage :\n",
    "  - Utilisation de `hashCode()` pour générer un code de hachage.\n",
    "  - Distribution uniforme des entrées pour améliorer les performances de recherche.\n",
    "- Implémentation avec des arbres :\n",
    "  - Arbres binaires de recherche pour maintenir les clés dans un ordre trié.\n",
    "  - Opérations de recherche, d'insertion et de suppression en temps logarithmique.\n",
    "- Les clés doivent implémenter l'interface `Comparable` pour définir un ordre naturel.\n",
    "- Utilisations courantes des Maps :\n",
    "  - Ajouter et supprimer des entrées.\n",
    "  - Rechercher un objet par sa clé.\n",
    "  - Récupérer les clés associées à une valeur.\n",
    "- Les Maps sont essentielles pour organiser et accéder efficacement aux données.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "Une `Map` est un outil essentiel en programmation, permettant d'associer une clé unique à une valeur spécifique. Chaque clé, étant unique, garantit que la méthode `equals()` retourne `false` lorsqu'elle compare deux clés différentes. De plus, pour les tables de hachage, la méthode `hashCode()` est utilisée pour générer un code de hachage pour chaque clé, ce qui permet de distribuer les entrées de manière uniforme et d'améliorer les performances de recherche. Les Maps peuvent également être implémentées à l'aide d'arbres, comme les arbres binaires de recherche, qui permettent de maintenir les clés dans un ordre trié et d'effectuer des opérations de recherche, d'insertion et de suppression en temps logarithmique. Pour ce faire, les clés doivent implémenter l'interface `Comparable`, ce qui permet de définir un ordre naturel entre elles. Les Maps sont couramment utilisées pour diverses opérations telles que l'ajout et la suppression d'entrées, la recherche d'un objet à partir de sa clé, ainsi que la récupération des clés associées à une valeur donnée. Ces fonctionnalités rendent les Maps particulièrement utiles pour organiser et accéder efficacement aux données.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "* En Java, il s'agit d'une interface implémentée notamment par :\n",
    "  * **HashMap** : Une table de hachage offrant un accès en $\\mathcal{O}(1)$.\n",
    "  * **TreeMap** : Un arbre équilibré qui ordonne les valeurs en fonction des clés :\n",
    "    * L'accès est en $\\mathcal{O}(\\log n)$ (où $n$ est le nombre d'éléments).\n",
    "    * Les objets doivent implémenter l'interface `Comparable`.\n",
    "    * Il est également possible de fournir un comparateur externe (instance de `Comparator`).\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "En Java, une `Map` est une interface cruciale, implémentée notamment par des classes comme `HashMap` et `TreeMap`. La `HashMap` utilise une table de hachage pour offrir un accès rapide aux éléments, généralement en temps constant $\\mathcal{O}(1)$. En revanche, la `TreeMap` utilise un arbre équilibré pour maintenir les clés dans un ordre trié, permettant des opérations de recherche, d'insertion et de suppression en temps logarithmique $\\mathcal{O}(\\log n)$. Pour que cela fonctionne, les objets clés doivent implémenter l'interface `Comparable`, ou bien un comparateur externe (`Comparator`) peut être fourni pour définir l'ordre des clés. Ces deux implémentations de `Map` sont essentielles pour organiser et accéder efficacement aux données en fonction des besoins spécifiques de performance et d'ordre.\n",
    ":::\n",
    "\n",
    "## L’interface Map<K,V>\n",
    "\n",
    "```\n",
    "void clear()\n",
    "boolean containsKey(Object key)\n",
    "boolean containsValue(Object value)\n",
    "Set<Map.Entry<K,V>> entrySet()\n",
    "boolean equals(Object o)\n",
    "V get(Object key)\n",
    "int hashCode()\n",
    "boolean isEmpty()\n",
    "Set<K> keySet()\n",
    "V put(K key, V value)\n",
    "void putAll(Map<? extends K,? extends V> t)\n",
    "V remove(Object key)\n",
    "int size()\n",
    "Collection<V> values()\n",
    "```\n",
    "\n",
    "## Fonctionnement de Map\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "* Par défaut, une `Map` stocke des instances de `Object`.\n",
    "* L'utilisation des génériques est possible et fortement recommandée.\n",
    "* Les couples clé/valeur sont manipulés via l'interface `Map.Entry`.\n",
    "  * Trois méthodes principales : `getKey()`, `getValue()`, `setValue()`.\n",
    "* La méthode `entrySet()` de `Map` retourne un ensemble (`Set`) de `Map.Entry`.\n",
    "* Pour garantir le bon fonctionnement, une clé ne peut être remplacée que par une clé égale (cf. `equals()`).\n",
    "* Conseil : effectuer une opération d'ajout suivie d'une suppression pour tester le comportement.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "En Java, une `Map` stocke par défaut des instances de `Object`, mais il est fortement recommandé d'utiliser des génériques pour spécifier les types de clés et de valeurs. Les couples clé/valeur sont manipulés via l'interface `Map.Entry`, qui fournit les méthodes `getKey()`, `getValue()`, et `setValue()`. La méthode `entrySet()` de `Map` retourne un ensemble (`Set`) de `Map.Entry`, permettant d'itérer sur les entrées de la `Map`. Il est crucial de s'assurer qu'une clé ne peut être remplacée que par une clé égale, conformément à la méthode `equals()`. Pour garantir le bon fonctionnement de la `Map`, il est conseillé de tester les opérations d'ajout et de suppression.\n",
    ":::\n",
    "\n",
    "## Exemple de Map"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "HashMap: {Ch2=Chien(){nom=Brutus}), Ch1=Chien(){nom=Rex}), Ch4=Chien(){nom=First}), Ch3=Chien(){nom=Medor})}\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "public final class Chien {\n",
    " public final String nom;\n",
    " public Chien(String nom) {this.nom = nom;}\n",
    " public String toString() {return \"Chien(){nom=\"+nom+\"})\";}\n",
    "}\n",
    "\n",
    "Map<String,Chien> map1 = new HashMap<String,Chien>();\n",
    "map1.put(\"Ch4\", new Chien( \"First\"));\n",
    "map1.put(\"Ch3\", new Chien( \"Medor\"));\n",
    "map1.put(\"Ch1\", new Chien( \"Rex\"));\n",
    "map1.put(\"Ch2\", new Chien( \"Medor\"));\n",
    "map1.put(\"Ch2\", new Chien( \"Brutus\"));\n",
    "System.out.println(\"HashMap: \"+map1);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Utilisation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Le chien Ch2 est Brutus\n",
      "TreeMap: {Ch1=Chien(){nom=Rex}), Ch2=Chien(){nom=Brutus}), Ch3=Chien(){nom=Medor}), Ch4=Chien(){nom=First})}\n",
      "Sub SortedMap: {Ch2=Chien(){nom=Brutus}), Ch3=Chien(){nom=Medor})}\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "\n",
    "System.out.println (\"Le chien Ch2 est \"+map1.get(\"Ch2\").nom);\n",
    "\n",
    "Map<String,Chien> map2 = new TreeMap<String,Chien>(map1);\n",
    "System.out.println(\"TreeMap: \"+map2);\n",
    "\n",
    "SortedMap<String,Chien> map3 = new TreeMap<String,Chien>(map1);\n",
    "System.out.println(\"Sub SortedMap: \"+map3.subMap(\"Ch2\",\"Ch3\"+\"\\0\"));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Parcourir une Map\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "* Pour parcourir une `Map` :\n",
    "  * Récupérer l'ensemble des clés avec `keySet()`.\n",
    "  * Parcourir cet ensemble à l'aide d'un itérateur ou d'une boucle `for each`.\n",
    "  * Pour chaque entrée, récupérer la clé avec `getKey()` et la valeur avec `getValue()`.\n",
    "  * La méthode `values()` retourne la collection des valeurs correspondantes.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "Pour parcourir une `Map` en Java, on commence par récupérer l'ensemble des clés à l'aide de la méthode `keySet()`. Ensuite, on peut parcourir cet ensemble soit avec un itérateur, soit avec une boucle `for each`. Pour chaque entrée, on peut obtenir la clé en utilisant la méthode `getKey()` et la valeur correspondante avec `getValue()`. De plus, la méthode `values()` permet de retourner directement la collection des valeurs contenues dans la `Map`. Cette approche facilite l'itération et la manipulation des données stockées dans la `Map`.\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ch2 :Chien(){nom=Brutus})Ch1 :Chien(){nom=Rex})Ch4 :Chien(){nom=First})Ch3 :Chien(){nom=Medor})"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "Set<Map.Entry<String,Chien>> setChiens = map1.entrySet();\n",
    "\n",
    "for (Map.Entry<String,Chien> uneEntree : setChiens)\n",
    "    System.out.print(uneEntree.getKey()+ \" :\" +uneEntree.getValue());"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Les critères de choix de classe\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "* Un des objectifs des programmes Java est la réutilisabilité.\n",
    "* Il est crucial de choisir la classe ou l'interface la plus adaptée.\n",
    "* Le programme doit être utilisable dans un maximum de cas possibles.\n",
    "* Pour cela, il est recommandé de :\n",
    "  1. Manipuler les objets via des interfaces aussi générales que possible pour les paramètres.\n",
    "  2. Choisir des types de retour pour les objets instances des classes les plus spécifiques possibles, offrant ainsi le plus de fonctionnalités.\n",
    "  3. Toutefois, ce dernier choix peut poser des problèmes en cas de changement d'implémentation ; il est donc préférable d'opter également pour des interfaces plus générales.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "En Java, l'un des objectifs principaux est de maximiser la réutilisabilité des programmes. Pour y parvenir, il est essentiel de choisir la classe ou l'interface la plus adaptée à chaque situation. Un programme doit être conçu pour être utilisable dans le plus grand nombre de cas possibles. Pour cela, il est recommandé de manipuler les objets via des interfaces aussi générales que possible pour les paramètres, afin de garantir une flexibilité maximale. En revanche, pour les types de retour, il est préférable de choisir des classes spécifiques offrant le plus de fonctionnalités. Cependant, ce choix peut poser des problèmes en cas de changement d'implémentation, d'où l'importance de privilégier également des interfaces plus générales pour maintenir la compatibilité et la flexibilité du code.\n",
    ":::\n",
    "\n",
    "## Arguments variables\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- **Varargs en Java** :\n",
    "  - Permettent de passer un nombre variable d'arguments du même type à une méthode.\n",
    "  - Simplifient le passage d'arguments sans créer explicitement un tableau ou une collection.\n",
    "  - Utilisation des varargs avec l'ellipse (`...`) après le type de l'argument.\n",
    "  - Flexibilité et praticité : la méthode peut être appelée avec n'importe quel nombre d'arguments de type `int`.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "Il n’est pas nécessaire d’utiliser une collection pour passer un ensemble d’arguments du même type à une méthode. En Java, vous pouvez utiliser les varargs (arguments variables) pour simplifier ce processus. Les varargs permettent de passer un nombre variable d’arguments à une méthode sans avoir à créer explicitement un tableau ou une collection. Pour déclarer une méthode avec des varargs, utilisez l’ellipse (...) après le type de l’argument. \n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "public static int somme (int... entiers) {\n",
    "  int total = 0 ;\n",
    "  for (int e:entiers) total+=e;\n",
    "  return total ;\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1+2 = 3\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "System.out.println(\"1+2 = \"+somme(1,2));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1+2+3+4 = 10\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "System.out.println(\"1+2+3+4 = \"+somme (1,2,3,4));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Implémentations Spécialisées de Set et Map pour les Enums\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "- EnumSet\n",
    "  - Implémentation de `Set` haute performance basée sur un bit-vecteur.\n",
    "  - Tous les éléments d'une instance de `EnumSet` doivent appartenir à un seul type d'énumération.\n",
    "- EnumMap\n",
    "  - Implémentation de `Map` haute performance basée sur un tableau.\n",
    "  - Toutes les clés d'une instance de `EnumMap` doivent appartenir à un seul type d'énumération.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "En Java, des implémentations spécialisées de Set et Map sont disponibles pour une utilisation avec les énumérations (enum). EnumSet est une implémentation de Set haute performance, basée sur un bit-vecteur, où tous les éléments doivent appartenir à un seul type d’énumération. Cette structure permet des opérations rapides et efficaces sur les ensembles d’énumérations. De même, EnumMap est une implémentation de Map haute performance, basée sur un tableau, où toutes les clés doivent également appartenir à un seul type d’énumération. Ces implémentations sont particulièrement utiles pour les cas où les performances et l’efficacité sont cruciales, tout en garantissant une gestion optimale des énumérations.\n",
    ":::\n",
    "\n",
    "### Exemple"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "public class Person {\n",
    "    public enum PetType {CAT, DOG};\n",
    "    private String name;\n",
    "    private EnumSet<PetType> pets;\n",
    "    public Person(String name, Set<PetType> petsTypes) {this.name=name; this.pets=EnumSet.copyOf(petsTypes);}\n",
    "    public boolean hasPet(PetType petType) {return pets.contains(petType);}\n",
    "    public String toString() {return name;}\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exemple"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "public enum Jour {\n",
    "  LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI, DIMANCHE;\n",
    "}\n",
    "\n",
    "EnumMap<Jour, Animal> animalParJour = new EnumMap<Jour, Animal>(Jour.class);\n",
    "\n",
    "animalParJour.put(Jour.MARDI,new Animal(\"Rex\"));\n",
    "animalParJour.put(Jour.VENDREDI,new Animal(\"Médor\"));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{MARDI=Animal(nom=Rex,age=-1,poids=-1), VENDREDI=Animal(nom=Médor,age=-1,poids=-1)}\n",
      "Animal(nom=Médor,age=-1,poids=-1)\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "System.out.println(animalParJour);\n",
    "System.out.println(animalParJour.get(Jour.VENDREDI));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Eclipse Collections\n",
    "\n",
    "::: {.content-visible when-profile=\"slides\"}\n",
    "* Une alternative externe au JDK, offrant une bibliothèque beaucoup plus complète :\n",
    "  * Eclipse Collections: https://eclipse.dev/collections/\n",
    "* Propose de nombreuses structures de données supplémentaires, à la fois mutables et immutables.\n",
    "* Intègre pleinement les expressions lambda et les streams pour une programmation fonctionnelle efficace.\n",
    ":::\n",
    "\n",
    "::: {.content-visible when-profile=\"notes\"}\n",
    "Eclipse Collections est une alternative externe au JDK, offrant une bibliothèque beaucoup plus complète pour les développeurs Java. Cette bibliothèque propose de nombreuses structures de données supplémentaires, qu'elles soient mutables ou immutables, permettant ainsi une plus grande flexibilité dans la gestion des collections. De plus, Eclipse Collections intègre pleinement les expressions lambda et les streams, facilitant ainsi une programmation fonctionnelle efficace. Pour en savoir plus, vous pouvez visiter le site officiel https://eclipse.dev/collections/\n",
    ":::\n",
    "\n",
    "### Exemple"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "%maven org.eclipse.collections:eclipse-collections-api:11.1.0\n",
    "%maven org.eclipse.collections:eclipse-collections:11.1.0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "import org.eclipse.collections.api.list.*;\n",
    "import org.eclipse.collections.api.list.primitive.*;\n",
    "import org.eclipse.collections.impl.factory.*;\n",
    "import org.eclipse.collections.impl.factory.primitive.IntLists;\n",
    "import java.util.stream.Collectors;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\u001b[36mintList;\u001b[0m: [1, 2, 3]"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "MutableIntList intList = IntLists.mutable.of(1, 2, 3);\n",
    "intList;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exemple"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[P1, P3]\n"
     ]
    }
   ],
   "source": [
    "//| echo: true\n",
    "//| output: true\n",
    "//| error: true\n",
    "MutableList<Person> mutableListWith =\n",
    "  Lists.mutable.with(\n",
    "    new Person(\"P1\",Set.of(Person.PetType.CAT)),\n",
    "    new Person(\"P2\",Set.of(Person.PetType.DOG)),\n",
    "    new Person(\"P3\",Set.of(Person.PetType.CAT, Person.PetType.DOG)));\n",
    "\n",
    "List<Person> peopleWithCats =\n",
    "  mutableListWith\n",
    "    .stream()\n",
    "    .filter(person -> person.hasPet(Person.PetType.CAT))\n",
    "    .collect(Collectors.toList());\n",
    "\n",
    "System.out.println(peopleWithCats);"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "java",
   "language": "java",
   "name": "java",
   "path": "/home/jovyan/.local/share/jupyter/kernels/conda-base-java"
  },
  "language_info": {
   "codemirror_mode": "java",
   "file_extension": ".jshell",
   "mimetype": "text/x-java-source",
   "name": "Java",
   "pygments_lexer": "java",
   "version": "21.0.8+9-LTS"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
