:: Enseignements :: Master :: M1 :: 2013-2014 :: Java Avancé ::
[LOGO]

java.util, full stream


Le but de ce TD est, dans un premier temps, d'utiliser l'API java.util.stream puis, dans un second temps, d'implanter la partie exécutable d'un petit language de requêtes.
Un sénateur des Etats-Unis d'amérique vient de compléter avec succès une campagne de dons lui permettant d'envisager sereinement les élections. En effet, un ensemble de généreux donateurs (Donor) ont répondu à son appel et ont versé différentes sommes d'argent, et il veut maintenant savoir des choses comme quel est le montant global des sommes versées, ou qui sont ses principaux donateurs.
Lorsqu'un donateur effectue une contribution, il signale son nom, son sexe, l'entreprise pour qui il travaille ainsi que la somme versée. Sous forme d'objet, on se retrouve avec les classes Donor et Company.


Exercice 1 - Un flux

  1. Avant de vraiment commencer, quel est le problème dans la façon dont l'attribut gender de la classe Donor est défini.
    Comment faire mieux ?
    Implanter les changements qui s'imposent.
  2. On souhaite calculer le montant global des sommes versées pour une liste de Donor.
    Où doit on écrire la méthode getTotalDonation ?
    Ecrire le code de cette méthode.
  3. On souhaite de plus trouver la liste de tous les Donor masculins pour une liste de Donor passée en paramètre.
    Ecrire la méthode getAllMales
    Noter que, comme le code qui teste si un donateur est masculin ou pas n'est pas très joli, il serait bien d'avoir une méthode isMale.
    Vérifier, avec les tests unitaires suivants, que tout va bien pour ces deux méthodes.
    DonorsTest
  4. En fait, il est possible d'utiliser une écriture plus concise pour les méthodes getTotalDonation et getAllMales en utilisant l'interface java.util.stream.Stream.
    Il existe une méthode stream() sur l'interface List qui permet d'obtenir un Stream. Ce stream possède des méthodes map, filter et collect.
    Expliquer à quoi servent les méthodes map, filter et collect et ré-implanter les méthodes getTotalDonation et getAllMales en utilisant un stream.
    Note: pour la méthode collect, il va falloir aider un peu Eclipse car celui-ci n'implante pas correctement l'inférence de type. Indiquer explicitement les types des arguments de la méthode permettant de créer le Collector est en général suffisant.
  5. On veut, de plus, une méthode getImportantDonors qui renvoie la liste des 10 plus importants donateurs ayant donné plus de 10 000 dollars triés de celui ayant donné le plus à celui ayant donné le moins.
    Implanter cette méthode en utilisant un stream.
  6. Enfin, on veut une méthode getDonorByCompany qui range dans une table de hachage les donateurs ayant la même entreprise (Company).

Exercice 2 - Mon SQL like

Bien sûr, écrire du code à chaque fois que le sénateur veut faire une extraction est une bonne nouvelle si on est payé à la ligne, mais sinon, bof.
Vous vous mettez donc d'accord pour créer un langage de requêtage qui va lui permettre d'interroger sa base de donateurs sans que vous soyez dans les parages.
Et comme vous aimez bien ré-inventer la roue, au lieu d'utiliser SQL, vous vous créez votre propre langage dont voici une description succinte.
       all                         // liste tous les donateurs
       name                        // liste le nom de tous les donateurs
       name limit 10               // liste les 10 premiers donateurs
       all sorted by name          // liste tous les donateurs triés
                                   // par ordre decroissant en fonction du nom
       all sorted by name limit 10 // meme chose qu'avant mais les 10 premiers
       all with name less than HHH // liste les donateurs dont le nom est inférieur
                                   // a HHH dans l'ordre lexicographique
     

Pour cela, vous utiliserez la classe Query qui représente, sous forme d'objet, une query textuelle.
La classe QueryParser déjà écrite, permet de prendre une chaîne de caractères et de créer un objet Query ou, si la chaîne de caractères est mal formée, de lever l'exception ParseException.
On ne vous demande pas de comprendre le code de la classe QueryParser, vous devez la considérer comme une boite noire qui crée un objet Query, seule la méthode execute doit être implantée.

Les tests unitaires associés sont ici: QueryTest.java

  1. On souhaite, dans un premier temps, implanter les projections uniquement en utilisant le champs selector d'une Query.
    Pourquoi la méthode execute renvoie une List<Object> ?
    On amerait plutôt une List<T> avec le bon T.
    Expliquer pourquoi remplacer List<Object> par List<T> rend le code unsafe.
    Comment doit on modifier la signature de la méthode execute pour que le code de execute ne soit plus unsafe ?
  2. Implanter les projections all, name, gender, company et amount.
  3. Implanter la notion de limit.
  4. Doit on faire le tri du sorted by avant ou après la projection ?
    Implanter le sorted by.
  5. Implanter le with en déléguant le traitement à la classe With.