Guava 19: Quoi de neuf?

Guava 19: quoi de neuf?

1. Vue d'ensemble

Google Guava fournit aux bibliothèques des utilitaires qui facilitent le développement Java. Dans ce didacticiel, nous examinerons les nouvelles fonctionnalités introduites dans lesGuava 19 release.

2. Modifications du packagecommon.base

2.1. Ajout des méthodes statiquesCharMatcher

CharMatcher, comme son nom l'indique, est utilisé pour vérifier si une chaîne correspond à un ensemble d'exigences.

String inputString = "someString789";
boolean result = CharMatcher.javaLetterOrDigit().matchesAllOf(inputString);

Dans l'exemple ci-dessus,result seratrue.

CharMatcher peut également être utilisé lorsque vous devez transformer des chaînes.

String number = "8 123 456 123";
String result = CharMatcher.whitespace().collapseFrom(number, '-');

Dans l'exemple ci-dessus,result sera «8-123-456-123».

À l'aide deCharMatcher, vous pouvez compter le nombre d'occurrences d'un caractère dans une chaîne donnée:

String number = "8 123 456 123";
int result = CharMatcher.digit().countIn(number);

Dans l'exemple ci-dessus,result sera égal à 10.

Les versions précédentes de Guava ont des constantes de correspondance telles queCharMatcher.WHITESPACE etCharMatcher.JAVA_LETTER_OR_DIGIT.

Dans Guava 19, celles-ci ont été remplacées par des méthodes équivalentes (CharMatcher.whitespace() etCharMatcher.javaLetterOrDigit(), respectivement). Cela a été modifié pour réduire le nombre de classes créées lorsqueCharMatcher est utilisé.

L'utilisation de méthodes d'usine statique permet aux classes d'être créées uniquement en fonction des besoins. Dans les versions futures, les constantes de matcher seront obsolètes et supprimées.

2.2. lazyStackTrace Méthode enThrowables

Cette méthode renvoie unList d'éléments stacktrace (lignes) d'unThrowable fourni. Cela peut être plus rapide que d'itérer sur le stacktrace complet (Throwable.getStackTrace()) si seule une partie est nécessaire, mais peut être plus lent si vous itérez sur le stacktrace complet.

IllegalArgumentException e = new IllegalArgumentException("Some argument is incorrect");
List stackTraceElements = Throwables.lazyStackTrace(e);

3. Modifications du packagecommon.collect

3.1. Ajout deFluentIterable.toMultiset()

Dans un exemple d'article précédent,Whats new in Guava 18, nous avons examinéFluentIterable. La méthodetoMultiset() est utilisée lorsque vous devez convertir unFluentIterable enImmutableMultiSet.

User[] usersArray = {new User(1L, "John", 45), new User(2L, "Max", 15)};
ImmutableMultiset users = FluentIterable.of(usersArray).toMultiset();

UnMultiset est une collection, commeSet, qui prend en charge l'égalité indépendante de l'ordre. La principale différence entre unSet et unMultiset est queMultiset peut contenir des éléments en double. Multiset stocke des éléments égaux en tant qu'occurrences du même élément unique, vous pouvez donc appelerMultiset.count(java.lang.Object) pour obtenir le nombre total d'occurrences d'un objet donné.

Jetons un coup d'oeil à quelques exemples:

List userNames = Arrays.asList("David", "Eugen", "Alex", "Alex", "David", "David", "David");

Multiset userNamesMultiset = HashMultiset.create(userNames);

assertEquals(7, userNamesMultiset.size());
assertEquals(4, userNamesMultiset.count("David"));
assertEquals(2, userNamesMultiset.count("Alex"));
assertEquals(1, userNamesMultiset.count("Eugen"));
assertThat(userNamesMultiset.elementSet(), anyOf(containsInAnyOrder("Alex", "David", "Eugen")));

Vous pouvez facilement déterminer le nombre d'éléments en double, ce qui est beaucoup plus propre qu'avec les collections Java standard.

3.2. Ajout deRangeSet.asDescendingSetOfRanges() etasDescendingMapOfRanges()

RangeSet est utilisé pour fonctionner avec des plages (intervalles) non vides. Nous pouvons décrire unRangeSet comme un ensemble de plages déconnectées et non vides. Lorsque vous ajoutez une nouvelle plage non vide à unRangeSet, toutes les plages connectées seront fusionnées et les plages vides seront ignorées:

Jetons un coup d'œil à quelques méthodes que nous pouvons utiliser pour créer de nouvelles plages:Range.closed(),Range.openClosed(),Range.closedOpen(),Range.open().

La différence entre eux est que les plages ouvertes n'incluent pas leurs points de terminaison. Ils ont une désignation différente en mathématiques. Les intervalles ouverts sont désignés par «(» ou «)», tandis que les plages fermées sont désignés par «[» ou «]».

Par exemple (0,5) signifie «toute valeur supérieure à 0 et inférieure à 5», tandis que (0,5] signifie «toute valeur supérieure à 0 et inférieure ou égale à 5»:

RangeSet rangeSet = TreeRangeSet.create();
rangeSet.add(Range.closed(1, 10));

Ici, nous avons ajouté la plage [1, 10] à nosRangeSet. Et maintenant, nous voulons l'étendre en ajoutant une nouvelle gamme:

rangeSet.add(Range.closed(5, 15));

Vous pouvez voir que ces deux plages sont connectées à 5, doncRangeSet les fusionnera en une nouvelle plage unique, [1, 15]:

rangeSet.add(Range.closedOpen(10, 17));

Ces plages sont connectées en 10 et seront donc fusionnées, ce qui donnera une plage fermée-ouverte, [1, 17). Vous pouvez vérifier si une valeur est incluse dans la plage ou non en utilisant la méthodecontains:

rangeSet.contains(15);

Cela renverratrue, car la plage [1,17) en contient 15. Essayons une autre valeur:

rangeSet.contains(17);

Cela renverrafalse, car la plage [1,17) ne contient pas son extrémité supérieure, 17. Vous pouvez également vérifier si range englobe une autre plage en utilisant la méthodeencloses:

rangeSet.encloses(Range.closed(2, 3));

Cela renverratrue car la plage [2,3] tombe complètement dans notre plage, [1,17).

Il existe quelques méthodes supplémentaires qui peuvent vous aider à utiliser des intervalles, telles queRange.greaterThan(),Range.lessThan(),Range.atLeast(),Range.atMost(). Les deux premiers ajouteront des intervalles ouverts, les deux derniers ajouteront des intervalles fermés. Par exemple:

rangeSet.add(Range.greaterThan(22));

Cela ajoutera un nouvel intervalle (22, + ∞) à vosRangeSet, car il n'a aucun lien avec d'autres intervalles.

Avec l'aide de nouvelles méthodes telles queasDescendingSetOfRanges (pourRangeSet) etasDescendingMapOfRanges (pourRangeSet), vous pouvez convertir unRangeSet enSet ouMap.

3.3. Ajout deLists.cartesianProduct(List…) etLists.cartesianProduct(List<List>>)

Un produit cartésien renvoie toutes les combinaisons possibles de deux ou plusieurs collections:

List first = Lists.newArrayList("value1", "value2");
List second = Lists.newArrayList("value3", "value4");

List> cartesianProduct = Lists.cartesianProduct(first, second);

List pair1 = Lists.newArrayList("value2", "value3");
List pair2 = Lists.newArrayList("value2", "value4");
List pair3 = Lists.newArrayList("value1", "value3");
List pair4 = Lists.newArrayList("value1", "value4");

assertThat(cartesianProduct, anyOf(containsInAnyOrder(pair1, pair2, pair3, pair4)));

Comme vous pouvez le voir dans cet exemple, la liste résultante contiendra toutes les combinaisons possibles des listes fournies.

3.4. Ajout deMaps.newLinkedHashMapWithExpectedSize(int)

La taille initiale d'unLinkedHashMap standard est 16 (vous pouvez le vérifier dans la source deLinkedHashMap). Lorsqu'il atteint le facteur de charge deHashMap (par défaut, 0,75),HashMap rehash et double sa taille. Mais si vous savez que votreHashMap gérera de nombreuses paires clé-valeur, vous pouvez spécifier une taille initiale supérieure à 16, vous permettant d'éviter des remaniements répétés:

LinkedHashMap someLinkedMap = Maps.newLinkedHashMapWithExpectedSize(512);

3.5. Multisets.removeOccurrences(Multiset, Multiset) ré-ajoutés

Cette méthode est utilisée pour supprimer les occurrences spécifiées dansMultiset:

Multiset multisetToModify = HashMultiset.create();
Multiset occurrencesToRemove = HashMultiset.create();

multisetToModify.add("John");
multisetToModify.add("Max");
multisetToModify.add("Alex");

occurrencesToRemove.add("Alex");
occurrencesToRemove.add("John");

Multisets.removeOccurrences(multisetToModify, occurrencesToRemove);

Après cette opération, seul «Max» restera enmultisetToModify.

Notez que, simultisetToModify contenait plusieurs instances d'un élément donné alors queoccurrencesToRemove ne contient qu'une seule instance de cet élément,removeOccurrences ne supprimera qu'une seule instance.

4. common.hash Package Changes

4.1. Ajouté Hashing.sha384 ()

La méthodeHashing.sha384() renvoie une fonction de hachage qui implémente l'algorithme SHA-384:

int inputData = 15;

HashFunction hashFunction = Hashing.sha384();
HashCode hashCode = hashFunction.hashInt(inputData);

Le SHA-384 a pour 15 est «0904b6277381dcfbddd… 2240a621b2b5e3cda8».

4.2. Ajout deHashing.concatenating(HashFunction, HashFunction, HashFunction…) etHashing.concatenating(Iterable<HashFunction>)

Avec l'aide des méthodesHashing.concatenating, vous concaténez les résultats d'une série de fonctions de hachage:

int inputData = 15;

HashFunction crc32Function = Hashing.crc32();
HashCode crc32HashCode = crc32Function.hashInt(inputData);

HashFunction hashFunction = Hashing.concatenating(Hashing.crc32(), Hashing.crc32());
HashCode concatenatedHashCode = hashFunction.hashInt(inputData);

LeconcatenatedHashCode résultant sera «4acf27794acf2779», qui est le même que lecrc32HashCode («4acf2779») concaténé avec lui-même.

Dans notre exemple, un seul algorithme de hachage a été utilisé pour plus de clarté. Ce n'est pas particulièrement utile, cependant. La combinaison de deux fonctions de hachage est utile lorsque vous devez renforcer votre hachage, car il ne peut être brisé que si deux de vos hachages sont brisés. Dans la plupart des cas, utilisez deux fonctions de hachage différentes.

5. Modifications du packagecommon.reflect

5.1. Ajout deTypeToken.isSubtypeOf

TypeToken est utilisé pour manipuler et interroger des types génériques même à l'exécution, en évitant lesproblems due to type erasure.

Java ne conserve pas les informations de type générique pour les objets lors de l'exécution, il est donc impossible de savoir si un objet donné a un type générique ou non. Mais avec l'aide de la réflexion, vous pouvez détecter des types génériques de méthodes ou de classes. TypeToken utilise cette solution de contournement pour vous permettre de travailler avec et d'interroger des types génériques sans code supplémentaire.

Dans notre exemple, vous pouvez voir que, sans la méthodeTypeTokenisAssignableFrom, retourneratrue même siArrayList<String> n'est pas assignable à partir deArrayList<Integer>:

ArrayList stringList = new ArrayList<>();
ArrayList intList = new ArrayList<>();
boolean isAssignableFrom = stringList.getClass().isAssignableFrom(intList.getClass());

Pour résoudre ce problème, nous pouvons le vérifier à l'aide deTypeToken.

TypeToken> listString = new TypeToken>() { };
TypeToken> integerString = new TypeToken>() { };

boolean isSupertypeOf = listString.isSupertypeOf(integerString);

Dans cet exemple,isSupertypeOf renverra faux.

Dans les versions précédentes de Guava, il existait la méthodeisAssignableFrom à cette fin, mais à partir de Guava 19, elle est obsolète au profit deisSupertypeOf. De plus, la méthodeisSubtypeOf(TypeToken) peut être utilisée pour déterminer si une classe est un sous-type d'une autre classe:

TypeToken> stringList = new TypeToken>() { };
TypeToken list = new TypeToken() { };

boolean isSubtypeOf = stringList.isSubtypeOf(list);

ArrayList est un sous-type deList, donc le résultat seratrue, comme prévu.

6. Modifications du packagecommon.io

6.1. Ajout deByteSource.sizeIfKnown()

Cette méthode retourne la taille de la source en octets, si elle peut être déterminée, sans ouvrir le flux de données:

ByteSource charSource = Files.asByteSource(file);
Optional size = charSource.sizeIfKnown();

6.2. Ajout deCharSource.length()

Dans la version précédente de Guava, il n'existait aucune méthode pour déterminer la longueur d'unCharSource. Vous pouvez maintenant utiliserCharSource.length() à cette fin.

6.3. Ajout deCharSource.lengthIfKnown()

Idem que pourByteSource, mais avecCharSource.lengthIfKnown() vous pouvez déterminer la longueur de votre fichier en caractères:

CharSource charSource = Files.asCharSource(file, Charsets.UTF_8);
Optional length = charSource.lengthIfKnown();

7. Conclusion

Guava 19 a introduit de nombreux ajouts et améliorations utiles dans sa bibliothèque en pleine expansion. Cela vaut bien la peine d'être envisagé pour votre prochain projet.

Les exemples de code de cet article sont disponibles dans lesGitHub repository.