Java 8 : du neuf dans les interfaces !

java8.pngParmi les nouveautés apportées par Java 8, on en trouve deux qui concernent les interfaces : les méthodes statiques et les méthodes par défaut.

Les méthodes statiques définies sur les interfaces fonctionnent exactement de la même façon que celles portées par les classes, il n'y a donc pas grand-chose à en dire. En revanche, les méthodes par défaut risquent de modifier assez profondément notre façon de concevoir nos API.

En Java 7 et antérieur, une méthode déclarée dans une interface ne fournit pas d'implémentation. Ce n'est qu'une signature, un contrat auquel chaque classe dérivée doit se conformer en fournissant une implémentation propre.

Mais il arrive que plusieurs classes similaires souhaitent partager une même implémentation de l'interface. Dans ce cas, deux stratégies sont possibles (celui qui a dit "copier/coller" viendra me voir à la fin du billet pour une retenue) :

  • Factoriser le code commun dans une classe abstraite, mais il n'est pas toujours possible de modifier la hiérarchie des classes
  • Extraire le code commun dans une classe utilitaire, sous forme de méthode statique (ex: Collections.sort()).

On conviendra qu'aucune des deux n'est réellement satisfaisante. Heureusement, Java 8 nous offre maintenant une troisième possibilité.

Lire la suite...

Industrialiser Tiles grâce aux Annotation Processors !

Apache Tiles est un framework populaire permettant d'assembler des pages JSP à partir de fragments réutilisables (ex: entête, menu, pied de page...). Un fichier de configuration permet de décrire la composition de chaque page, et de lui assigner un nom logique. C'est ce même nom logique qui permet ensuite, depuis un contrôleur (Servlet pure, Spring MVC...), de demander à Tiles de construire et d'afficher la page correspondante.

Malheureusement, suite à des renommages - ou tout simplement par étourderie - il est facile de faire des erreurs dans les noms des vues au niveau des contrôleurs. Et l'erreur n'est visible qu'une fois l'application déployée...

Je vous propose ici une technique pour générer automatiquement des constantes Java correspondant aux noms des vues Tiles. Ainsi, plus de typos !

Lire la suite...

Les annotations @Repetables en Java 8 !

java8.jpgComme vous le savez (dans le cas contraire, foncez regarder ma conférence sur les annotations !), il est actuellement interdit de placer plusieurs fois la même annotation sur un élément donné.

Mais ça va changer avec Java 8 !

Lire la suite...

Implémenter le pattern Session Object avec Spring MVC

HTTP est un protocole déconnecté : un client se connecte à un serveur, lui transmet une requête, attend une réponse, et se déconnecte. Bonjour, au revoir, et on recommence à zéro.

Pour servir des documents sur un réseau, c'est parfait ; mais pour interagir avec une application web professionnelle, c'est un peu limité. L'utilisateur apprécie qu'on se rappelle de lui tout au long de sa session de travail, qui peut nécessiter de nombreux cycles requête/réponse.
Pour conserver ce contexte applicatif entre les requêtes, le serveur propose donc la notion de Session. Chaque utilisateur se voit ainsi attribuer un petit coffre-fort personnel, dans lequel les données qui le concernent sont stockées entre les requêtes.

Lire la suite...

Restangular : une architecture full-REST avec Restlet et AngularJS

Il y a un an, je vous proposais d'intégrer AngularJS et Spring MVC. L'excellent support du format JSON par ce dernier en faisait une technologie de choix pour exposer des ressources en REST/JSON, format favori d'AngularJS.

Un an plus tard, je découvre Restlet, un peu par hasard.
Je lis la documentation, mon intérêt s'éveille, je fais quelques tests... puis je repense à AngularJS.

A ma gauche, un framework spécifiquement conçu pour exposer des ressources en REST ; à ma droite, un framework qui consomme principalement des ressources REST... Aurais-je trouvé le couple parfait ? Vite, un prototype !

Dans cet article, je vous présente le résultat de ma petite expérience : une micro-application (la classique Todo-list) à l'architecture 100% RESTful, basée sur Restlet et AngularJS, et saupoudrée d'un peu de Bootstrap 3 pour le style graphique (voir capture d'écran ci-dessous).

Vous avez fait le plein de café et de tartines ? Alors c'est parti, suivez le guide !

Lire la suite...

Astuce : itération inverse

Une petite astuce en passant : comment parcourir une liste en sens inverse, à l'aide d'un itérateur ?
En utilisant un ListIterator, qui dispose de méthodes hasPrevious() et previous() :

List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
ListIterator<Integer> it = nums.listIterator(nums.size());
while(it.hasPrevious()) {
    Integer num = it.previous();
    System.out.println(num);
}
5
4
3
2
1

Ca peut toujours servir !

Coding challenge : maman les petits avions

Aujourd'hui, je vous propose de jouer aux petits avions, et de vérifier quel prototype vole le mieux.

Pour les départager, nous allons nous appuyer sur la Suite de Syracuse :
En partant d'un nombre initial (entier positif), pour obtenir le suivant :

  • s’il est pair, on le divise par 2 ;
  • s’il est impair, on le multiplie par 3 et on ajoute 1.

On répète l'opération jusqu'à obtenir le nombre 1 (la suite est convergente).

On définit ensuite les termes suivants :

  • le temps de vol total : c'est la longueur de la séquence obtenue.
  • le temps de vol en altitude : c'est la période continue, à partir du décollage, pendant laquelle l'avion reste à une altitude supérieure ou égale à l'altitude initiale (voir exemple ci-dessous).
  • l'altitude maximale : c'est la valeur maximale de la séquence.

Prenons l'exemple du nombre initial 15.

  • Sa séquence est [15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]
  • Son temps de vol total est de 18
  • Son temps de vol en altitude est de 11 ([15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20] = 11 éléments)
  • Son altitude maximale est de 160

Voyons maintenant comment tester nos différents prototypes d'avions.
Chaque prototype a évidemment un nom de code top secret, comme "Enterprise" ou "FauconMillenium". En additionnant les valeurs des lettres qui composent leurs noms, nous sommes capables de déterminer leur nombre initial.
Ainsi : "Enterprise" vaut 1057, et "FauconMillenium" vaut 1544.

Je vous laisse calculer quel modèle vole le mieux, et inventer vos propres prototypes !

Idéalement, il suffirait d'appeler une méthode en lui passant le nom du prototype, pour calculer (et éventuellement afficher) les trois indicateurs.
(Tous les langages bienvenus, utilisez Gist, Pastebin ou autre si votre code est volumineux)

Lire la suite...

Gagnez du temps avec Joda Time !

La représentation et la manipulation des dates et heures est un point notoirement faible de Java depuis sa version 1.0 - et je ne vous parle pas des Timezones...
Il existe heureusement une petite librairie fort pratique pour combler ce vide sidérant : Joda Time. Développée par Stephen Colebourne, elle est en passe d'être standardisée au sein du JDK sous la JSR-310 ("Date & Time API").

Si vous ne la connaissez pas encore, suivez le guide !

Lire la suite...

Devs vs Threads : une comparaison pifométrique

Dans la religion méthodologie Scrum, les spécifications du produit à développer ne sont pas rédigées dans leur intégralité au début du projet, mais au contraire fournies par le client au fur et à mesure de l'avancement du développement, afin de lui offrir une plus grande réactivité.
Le périmètre courant du projet est matérialisé par le "product backlog", c'est-à-dire un flux priorisé de fonctionnalités à développer, alimenté en permanence par le client, et consommé en flux tendu par l'équipe de développement.

Mine de rien, on est là en plein pattern producteur-consommateur. On pourrait même y voir une certaine similarité avec le fonctionnement d'un ThreadPool, les thread (les développeurs) traitant des jobs (les fonctionnalités) dans leur ordre de soumission.

Question : les bonnes pratiques associées à la gestion des thread pools (en particulier leur dimensionnement) pourraient-elles être appliquées aux équipes de développement Scrum ?

Lire la suite...

TreeSet / TreeMap : petit changement en Java 7

Jusqu'à Java 6 inclus, TreeMap et TreeSet avaient un comportement rigolo, pouvant fournir matière à quiz ou question d'entretien technique.

A votre avis, que fait ce bout de code ?

TreeSet set = new TreeSet();
set.add(new Object());
set.add(new Object());
System.out.println(set.size());

A l'exécution, on obtient une ClassCastException... à la ligne 3.
C'est-à-dire l'insertion du premier objet se passe bien, mais que la seconde provoque une exception.

La raison en est simple : un TreeSet (ou une TreeMap) étant implémenté sous forme d'arbre binaire, il doit comparer les objets entre eux pour les organiser. Or, nous voyons dans le code que les objets insérés n'implémentent pas Comparable, et qu'aucun Comparator n'est fourni au TreeSet.

Le premier objet étant... le premier justement, et donc le seul dans la structure, aucune comparaison n'est effectuée : il devient simplement la racine de l'arbre. A partir du second objet, une comparaison devient nécessaire, et les objets sont donc "castés" en Comparable... ce qui provoque une ClassCastException.

Funky, mais logique, quelque part.

Et bien, tout ceci est fini en Java 7 : on obtient une exception dès la première insertion.
C'est moins drôle, mais ce nouveau comportement est sans doute plus sain. On ne s'en plaindra donc pas.

Et puis, maintenant vous avez une nouvelle anecdote pour épater les convives dans les dîners mondains :)

- page 2 de 11 -