mai
2012
Dans un programme, il est hyper fréquent de devoir décomposer une String en différents items (token). On peut le faire en Java standard mais c’est vite complexe, surtout lorsqu’on veut ajouter des fonctionnalités avancées. Guava répond à ce problème à l’aide des Splitters.
Pour illustrer la suite, prenons un vrai exemple simple, tiré d’une de mes applications Web. Je m’intéresse à une page permettant d’avoir la météo d’une ville donnée, dans une langue donnée, à une heure donnée, dans une unité de mesure donnée, etc. La page s’appelle directement à l’aide de l’adresse suivante :
1 | http://www.monserveur.fr/meteo/paris/fr/14h00/celcius/yellow/ /etc |
Disons que mon application dispose déjà de fonctionnalités pour isoler le domaine et me laisser uniquement la sous-partie suivante à traiter (qui commence par un slash) :
1 | /meteo/paris/fr/14h00/celcius/yellow/ /etc |
pour les besoins de la démonstration, on suppose que le navigateur accepte les espaces. Ce qui m’intéresse, c’est d’avoir une liste avec tous les paramètres utilisés :
- action : meteo
- ville : paris
- langue : fr
- heure : 14h00
- unité : celcius
- skin : yellow
- etc.
Ici, on comprend bien que le caractère « / » va me servir de séparateur. Pour l’utiliser avec Guava, il suffit de définir un splitter :
1 | Splitter splitter1 = Splitter.on("/"); |
Puis de l’utiliser sur la String :
1 | Iterable<String> paramsView = splitter1.split("/meteo/paris/fr/14h00/celcius/yellow/ /etc"); |
Comme je l’avais déjà expliqué dans un autre billet, on voit que le splitter renvoie une vue (lazzy) et non une liste. Dans la suite, et pour des raisons pratiques, je vais transformer ma vue en liste.
1 | List<String> params = newArrayList(splitter1.split("/meteo/paris/fr/14h00/celcius/yellow/ /etc")); |
Bien entendu, je fais l’import static de newArrayList() :
1 | import static com.google.common.collect.Lists.newArrayList; |
Le code complet va ressembler au suivant :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @Test public void testSimpleSplitter() { // Arrange final String url = "/meteo/paris/fr/14h00/celcius/yellow/ /etc"; final String separator = "/"; final List<String> listeAttendue = newArrayList("", "meteo", "paris", "fr", "14h00", "celcius", "yellow"," ", "etc"); // Act final Splitter splitter = Splitter.on(separator); List<String> params = newArrayList(splitter.split(url)); for (String s : params) { System.out.println("param : '" + s + "'"); } // Assert Assert.assertEquals(listeAttendue, params); } |
Le test passe au vert et affiche :
1 2 3 4 5 6 7 8 9 | param : '' param : 'meteo' param : 'paris' param : 'fr' param : '14h00' param : 'celcius' param : 'yellow' param : ' ' param : 'etc' |
Le plus gros du travail est fait, mais la liste peut être améliorée. En effet, le huitième élément est un espace sans information qui pollue la liste. On va donc le réduire à l’aide de « trimResults() » :
1 | Splitter splitter = Splitter.on(separator).trimResults(); |
Le test devient donc :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @Test public void testTrimSplitter() { // Arrange final String url = "/meteo/paris/fr/14h00/celcius/yellow/ /etc"; final String separator = "/"; final List<String> listeAttendue = newArrayList("", "meteo", "paris", "fr", "14h00", "celcius", "yellow"," ", "etc"); // Act final Splitter splitter = Splitter.on(separator).trimResults(); List<String> params = newArrayList(splitter.split(url)); for (String s : params) { System.out.println("param : '" + s + "'"); } // Assert Assert.assertEquals(listeAttendue, params); } |
Le test passe au vert et affiche :
1 2 3 4 5 6 7 8 9 | param : '' param : 'meteo' param : 'paris' param : 'fr' param : '14h00' param : 'celcius' param : 'yellow' param : '' param : 'etc' |
Là encore, la liste est polluée, cette fois par des items vides en première et huitième position. On va demander à Guava de sauter ces éléments :
1 | Splitter splitter = Splitter.on(separator).trimResults().omitEmptyStrings(); |
Ce qui donne :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @Test public void testOmitSplitter() { // Arrange final String url = "/meteo/paris/fr/14h00/celcius/yellow/ /etc"; final String separator = "/"; final List<String> listeAttendue = newArrayList("meteo", "paris", "fr", "14h00", "celcius", "yellow", "etc"); // Act final Splitter splitter = Splitter.on(separator).trimResults().omitEmptyStrings(); List<String> params = newArrayList(splitter.split(url)); for (String s : params) { System.out.println("param : '" + s + "'"); } // Assert Assert.assertEquals(listeAttendue, params); } |
Et sans surprise le test passe au vert et affiche :
1 2 3 4 5 6 7 | param : 'meteo' param : 'paris' param : 'fr' param : '14h00' param : 'celcius' param : 'yellow' param : 'etc' |
Et voilà…
Mais ça n’est pas fini. Reprenons l’exemple. Le premier paramètre correspond à mon action (afficher la météo) et les paramètres suivant correspondent à des réglages. Disons que, pour des raisons qui m’appartiennent (comme les performances), je souhaite uniquement dissocier les N premiers items. Pour cela j’utilise la méthode limit() qui, comme son nom l’indique, permet de limiter le nombre d’items trouvés/cherchés.
1 | Splitter splitter = Splitter.on(separator).omitEmptyStrings().limit(2); |
Ce qui nous donne :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @Test public void testLimitSplitter() { // Arrange final String url = "/meteo/paris/fr/14h00/celcius/yellow/ /etc"; final String separator = "/"; final List<String> listeAttendue = newArrayList("meteo", "paris/fr/14h00/celcius/yellow/ /etc"); // Act final Splitter splitter = Splitter.on(separator).omitEmptyStrings().limit(2); List<String> params = newArrayList(splitter.split(url)); for (String s : params) { System.out.println("param : '" + s + "'"); } // Assert Assert.assertEquals(listeAttendue, params); } |
Le test est vert et affiche :
1 2 | param : 'meteo' param : 'paris/fr/14h00/celcius/yellow/ /etc' |
Commentaires récents
- Le Stop watch de Guava dans
- Le Stop watch de Guava dans
- Le Stop watch de Guava dans