I. Pretty Time
Guillaume Laforge, leader du projet Groovy nous a présenté la librairie PrettyTime développée par Lincoln Baxter III qui travaille chez OcpSoft et RedHat. Celle-ci permet de présenter des dates sous forme de dates relatives du type : à l’instant, dans 10 minutes, il y a 3 heures. Guillaume l’utilise sur son blog pour afficher la date des posts ce qui permet d’indiquer la date de la façon suivante : Posted on 09 November, 2011 (2 days ago). La librairie est constituée d’un jar n’a pas de dépendance. Elle supporte 18 langues dont le français et l’anglais et est très simple à utiliser.
// on initialise avec une date de reference PrettyTime t = new PrettyTime(new Date(1000 * 60 * 12), new Locale("fr")); // on formate une date par rapport a cette date de reference assertEquals("il y a 12 minutes", t.format(new Date(0)));
on peut utiliser facilement PrettyTime avec Grails ou JSF.
II. GPars
GPars (prononcez Jeepers) est une librairie permettant de s’adapter au multi-processeurs et au multi-coeurs en faisant de la programmation concurrente.
il est difficile de bien utiliser ce que le JDK propose : threads / synchronize / wait-notify-notifyAll, qui peuvent conduire à
- des dead-locks, des live-locks (in interblocage qui consomme du CPU), des race conditions ou l’épuisement de ressources
- des problèmes de gestion d’accès à la mémoire partagée
Pour éviter ces problèmes, GPars propose d’utiliser l’immuabilité et le passage de messages au travers des paradigmes suivants
- Acteurs
- Fork/Join
- Collections parallèles
- Executors
- Dataflow
- Agent – an thread-safe reference to mutable state
- STM (Software Transactional Memory)
- CSP
un exemple avec les fonctions parallèles pour les collections
@Grab('org.codehaus.gpars:gpars:0.12') import static groovyx.gpars.GParsPool.withPool defnums=1..100000 withPool(5){ def squares=nums.collectParallel{it**2} .grepParallel{it%7it%5} .grepParallel{it%30} println squares[0..3]+"..."+squares[-3..-1] assertsquares[0..3]==[36,144,1089,1296] }
on utilise un pool de taille nombre de coeurs + 1 afin de maximiser l’utilisation du CPU car souvent on a un thread qui sert à la coordination des autres et qui consomme peu de ressources. GPars a comme dépendance les librairies jsr166y et extra166y. Il dispose d’une API Java et d’une API Groovy.
Selon le problème que l’on a à résoudre on utilisera des outils différents. Cela est bien présenté par le graphe suivant.
les slides de la présentation de Guillaume ici
III. Project Lombok (ou comment cacher la plomberie)
Florent Ramière de la société Jaxio nous a présenté Lombok, “un outil qui sert à enlever la plomberie”. Il s’agit d’un plugin eclipse qui va générer du code technique grâce à des annotations, le source ne sera donc pas pollué par ce code technique qui existera néanmoins dans le bytecode après compilation. En utilisant Lombok on pourra donc clarifier son code et se concentrer sur d’autres parties de son code. On peut bien sûr utiliser les assistants eclipse pour générer un code similaireà celui généré par Lombok.
on dispose notamment des annotations suivantes
@Getter
@Setter
@EqualsAndHashCode
@RequiredArgsConstructor un constructeur avec tous les champs finaux
@Data est un raccourci pour @ToString, @EqualsAndHashCode, @Getter sur tous les champs et @Setter sur tous les champs non-finaux, et @RequiredArgsConstructor! à utiliser pour ses beans.
@Delegate permet de déléguer toutes les méthodes publiques de l’attribut annoté, excepté les méthodes présentes dans java.lang.Object.
@Log et ses variantes @CommonsLog, @Log4j et @Slf4j permet d’instancier une variable statique privée log
@Synchronized permet de générer un bloc synchronize sur une variable privée $lock ou $LOCK (dans le cas d’une méthode statique)
val est un type Lombok permettant d’avoir des variables ‘final’ et de bénéficier de l’inférence de type.On peut ainsi écrire
val map = new HashMap();
la page suivante explique très bien le code généré par Lombok. on peut d’ailleurs si besoin générer ce code en utilisant delombok (pour GWT notamment ou si l’on veut utiliser le code générer sans dépendre de lombok). lombok-pg est un ensemble d’extensions pour lombok.
Lombok peut également être utilisé via ant, maven ou javac.
Au détour de ses démonstrations, florent nous a également conseillé l’outil awaitility qui permet de faire des tests sur du code asynchrone
IV. Apache Commons Configuration
Emmanuel Bourg est membre de la fondation Apache et est commiter sur le projet Apache Commons Configuratio qu’il est venu nous présenter. Il s’agit d’une abstraction de la configuration d’une application qui présente une interface simple de type clé/valeur pour les données. Elle permet de gérer différents formats de données et des transformations dans les types voulus.
On peut gérer un format Properties amélioré
list1=val1,val2,val3 list2=val1 list2=val2 list2=val3 include=chunk.properties
On peut également utiliser des fichiers XML, Property List XML, Ini ou encore une base données.
Plusieurs formats sont prévus : OGDL, YAML, JSON, Registry Windows, Binary Property List. Les contributions sont les bienvenues si vous voulez aider à ajouter le support des nouveaux formats. On peut combiner plusieurs configurations grâce à CompositeConfiguration. On peut également utiliser un descripteur de configuration. Commons Configuration s’intègre très bien avec la librairie d’abstraction de systeme de fichiers Apache Commons VFS.
Sauvegarde automatique
PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties"); config.setAutoSave(true);
Rechargement automatique (on peut également déclencher le rechargement)
PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties"); config.setReloadingStrategy(new FileChangedReloadingStrategy());
V. Guava (N’aime pas les null)
Thierry Leriche-Dessirier (Indépendant) et Etienne Neveu (SFEIR) nous ont fait faire un tour du propriétaire de Guava, la librairie utilitaire de Google autrefois nommée google-collections.
Factory methods
Inférence de type : grâce à des factory statiques on peut écrire
List primeNumbers = newArrayList(); Set colors = newTreeSet(); Map ages = newHashMap();
ce qui n’est plus si intéressant que ca en Java 7 avec la notation diamant.
L’initialisation de collection est également facilitée
List dogs = newArrayList(Dog1, Dog2, Dog3)
Programmation fonctionnelle
On peut filtrer une collection grâce à un prédicat
Iterable maleDogs = Iterables.filter(dogs, new Predicate() { public boolean apply(Dog dog) { return dog.getSex() == MALE; } });
un predicat peut utiliser les prédicats and, in, or, not déjà définis dans la classe Predicates
boolean isMilouInBoth = and(in(dogs), in(superDogs)) .apply(new Dog("Milou"));
on peut transformer les elements d’une liste en utilisant une Function
List chiens = Lists.transform(dogs, new Function() { public Chien apply(Dog dog) { return new Chien(dog.getName()); } });
Attention ce sont des vues qui sont retournées. cela peremt d’avoir du lazy-loading mais la conversion sera faite autant de fois que nécessaire.
Iterables.find utilise le même prédicat que pour Iterables filter mais renvoit le premier objet correspondant au predicat ou un objet par défaut si rien ne correspondait au prédicat.
Dog firstMale = Iterables.find(dogs, malePredicate, DEFAULT);
collections immuables
on a des syntaxes plus concises que la syntaxe standard tout en proposant de la copie défensive.
ImmutableSet.of(1, 2, 3, 5, 7); ImmutableSet.copyOf(favoriteColors)
base.Objects
cette classe propose d’aider à la simplification de l’écriture des méthodes equals(), hashcode() ou toString()
//equals Objects.equal(name, that.name) && Objects.equal(weight, that.weight) && sex == that.sex; // hashcode Objects.hashCode(name, weight, sex); //toString Objects.toStringHelper(this) .add("name", name) .add("weight", weight) .add("sex", sex) .toString();
on peut créer facilement un comparateur
public int compareTo(Dog other) { return ComparisonChain.start() .compare(name, other.name) .compare(weight, other.weight) .compare(sex, other.sex) .result(); }
base.Preconditions
on peut vérifier des paramètres
this.currency = checkNotNull(currency, "currency cannot be null"); checkArgument(amount.signum() >= 0, "must be positive: %s", amount);
base.CharMatcher
il s’agit d’un outil permettant d’exprimer une expression régulière en language naturel. Il permet de remplacer avantageusement StringUtils des Apache Commons.
Collections
on dispose de collections n’existant pas dans le JDK
MultiMap : il s’agit d’une map pouvant avoir plusieurs valeurs pour une même clé
Multimap favoriteColors = HashMultimap.create();
BiMap : il s’agit d’une map pouvant n’ayant pas 2 fois la même valeur
BiMap favoriteColors = HashBiMap.create();
Multiset: il s’agit d’un set pouvant contenir plusieurs fois la même valeur (on peut même connaître le nombre de doublons)
Multiset primeNumbers = HashMultiset.create();
Joiner et Splitter permettent de manipuler les conversions entre chaine de caractères et liste de String.
En utilisant Joiner, on aura une NullPointerException si un des éléments de la liste vaut null mais l’on pourra utiliser skipNulls() ou userForNull(MY_DEFAULT) pour spécifier le comportement lorsque l’on rencontre un null.
List
En utilisant Splitter on peut nettoyer le résultat en utilisant trimResults() et omitEmptyStrings()
Iterable
Cache
Memoization
la memoization permet de garder en cache une unique valeur. l’exemple donné était la mise en cache du numéro de version du dernier jdk. On défini via l’utilisation d’un Supplier comment aller chercher la valeur qui nous intéresse. Celle valeur ne sera récupérée que lors du premier appel (lazy loading). Les appels suivant utiliserons le cache.
private Supplier
On peut également préciser une durée de validité du cache avec memoizeWithExpiration()
Key-Value
On peut construire un Cache à plusieurs entrées grâce aux classes CacheBuilder et CacheLoader
private Cache<Long, Film> filmCache = CacheBuilder.newBuilder() .maximumSize(2000) .expireAfterWrite(30, TimeUnit.MINUTES) .build(new CacheLoader<Long, Film>() { public Film load(Long filmId) { return imdbWebService.loadFilmInfos(filmId); } });
Concurrent
Guava propose d’étendre Future avec la classe ListenableFuture. On peut ainsi associer un listener à un Future.
ListenableFuture
On peut également faire de la programmation asynchrone grâce à FutureCallback. cela permet d’isoler le traitement des exceptions.
Futures.addCallback(future, new FutureCallback
pour utiliser des ListenableFuture on utilise un ListeningExecutorService de la façon suivante.
ListeningExecutorService executor = MoreExecutors.listeningDecorator(executor); public ListenableFuture
En utilisant les méthodes proposées par Futures on peut facilement proposer des méthodes non bloquantes qui renvoient un Future au lieu d’une liste de notes. Cela permet au programme appelant de ne pas bloquer pendant la récupération des notes et d’effectuer d’autres traitements pendant celle-ci.
ListenableFuture <List