Apache Commons-collecties versus Google Guava

1. Overzicht

In deze tutorial zullen we het vergelijken twee op Java gebaseerde open source-bibliotheken: Apache Commons en Google Guava. Beide bibliotheken hebben een rijke functieset met veel hulpprogramma-API's, voornamelijk in het verzamelingen- en I / O-gebied.

Om het kort te houden, beschrijven we hier slechts een handvol van de meest gebruikte uit het verzamelingsraamwerk, samen met codevoorbeelden. We zullen ook een samenvatting van hun verschillen zien.

Bovendien, we hebben een verzameling artikelen voor een diepe duik in verschillende commons- en Guava-hulpprogramma's.

2. Een korte geschiedenis van de twee bibliotheken

Google Guava is een Google-project, voornamelijk ontwikkeld door de ingenieurs van de organisatie, hoewel het nu open source is. De De belangrijkste motivatie om ermee te beginnen was om generieke geneesmiddelen die in JDK 1.5 zijn geïntroduceerd, op te nemen in Java Collections Framework, of JCF, en zijn mogelijkheden vergroten.

Sinds de oprichting heeft de bibliotheek zijn mogelijkheden uitgebreid en omvat nu grafieken, functioneel programmeren, bereikobjecten, caching en Draad manipulatie.

Apache Commons begon als een Jakarta-project om de kern-API voor Java-collecties aan te vullen en werd uiteindelijk een project van de Apache Software Foundation. In de loop der jaren is het uitgegroeid tot een uitgebreid repertoire van herbruikbare Java-componenten op verschillende andere gebieden, waaronder (maar niet beperkt tot) beeldvorming, I / O, cryptografie, caching, netwerken, validatie en pooling van objecten.

Omdat dit een open-sourceproject is, blijven ontwikkelaars uit de Apache-gemeenschap deze bibliotheek uitbreiden om de mogelijkheden ervan uit te breiden. Echter, ze besteden veel aandacht aan het behouden van achterwaartse compatibiliteit.

3. Maven Afhankelijkheid

Om Guava op te nemen, moeten we zijn afhankelijkheid toevoegen aan onze pom.xml:

 com.google.guava guave 29.0-jre 

De laatste versie-informatie is te vinden op Maven.

Voor Apache Commons is het een beetje anders. Afhankelijk van het hulpprogramma dat we willen gebruiken, moeten we dat specifieke hulpprogramma toevoegen. Voor verzamelingen moeten we bijvoorbeeld toevoegen:

 org.apache.commons commons-collections4 4.4 

In onze codevoorbeelden gebruiken we commons-collecties4.

Laten we nu in het leuke gedeelte springen!

4. Bidirectionele kaarten

Kaarten die toegankelijk zijn met hun sleutels, evenals waarden, worden bidirectionele kaarten genoemd. JCF heeft deze functie niet.

Laten we eens kijken hoe onze twee technologieën ze bieden. In beide gevallen nemen we een voorbeeld van dagen van de week om de naam van de dag op basis van het nummer te krijgen en vice versa.

4.1. Guava's BiMap

Guava biedt een interface - BiMap, als een bidirectionele kaart. Het kan worden geïnstantieerd met een van zijn implementaties EnumBiMap, EnumHashBiMap, HashBiMap, of ImmutableBiMap.

Hier gebruiken we HashBiMap:

BiMap daysOfWeek = HashBiMap.create ();

Het vullen is vergelijkbaar met elke kaart in Java:

daysOfWeek.put (1, "Maandag"); daysOfWeek.put (2, "dinsdag"); daysOfWeek.put (3; "woensdag"); daysOfWeek.put (4; "donderdag"); daysOfWeek.put (5; "vrijdag"); daysOfWeek.put (6; "zaterdag"); daysOfWeek.put (7; "zondag");

En hier zijn enkele JUnit-tests om het concept te bewijzen:

@Test openbare leegte gegevenBiMap_whenValue_thenKeyReturned () {assertEquals (Integer.valueOf (7), daysOfWeek.inverse (). Get ("Sunday")); } @Test openbare leegte gegevenBiMap_whenKey_thenValueReturned () {assertEquals ("Tuesday", daysOfWeek.get (2)); }

4.2. Apache's BidiMap

Op dezelfde manier biedt Apache ons zijn BidiMap koppel:

BidiMap daysOfWeek = nieuwe TreeBidiMap ();

Hier gebruiken we TreeBidiMap. Er zijn echter andere implementaties, zoals DualHashBidiMap en DualTreeBidiMap ook.

Om het te vullen, kunnen we de waarden plaatsen zoals we deden voor BiMap bovenstaande.

Het gebruik is ook redelijk vergelijkbaar:

@Test openbare leegte gegevenBidiMap_whenValue_thenKeyReturned () {assertEquals (Integer.valueOf (7), daysOfWeek.inverseBidiMap (). Get ("Sunday")); } @Test openbare leegte gegevenBidiMap_whenKey_thenValueReturned () {assertEquals ("Tuesday", daysOfWeek.get (2)); }

In een paar eenvoudige prestatietests wordt deze bidirectionele kaart bleef alleen achter bij zijn Guava-tegenhanger in inserties. Het was veel sneller bij het ophalen van zowel sleutels als waarden.

5. Wijs sleutels toe aan meerdere waarden

Voor een use case waarin we meerdere sleutels aan verschillende waarden willen toewijzen, zoals een verzameling boodschappenwagentjes voor groenten en fruit, bieden de twee bibliotheken ons unieke oplossingen.

5.1. Guava's MultiMap

Laten we eerst eens kijken hoe we kunnen instantiëren en initialiseren MultiMap:

Multimap groceryCart = ArrayListMultimap.create (); groceryCart.put ("Fruit", "Appel"); groceryCart.put ("Fruit", "Druiven"); groceryCart.put ("Fruit", "Aardbeien"); groceryCart.put ("Groenten", "Spinazie"); groceryCart.put ("Groenten", "Kool");

Vervolgens gebruiken we een aantal JUnit-tests om het in actie te zien:

@Test openbare leegte gegevenMultiValuedMap_whenFruitsFetched_thenFruitsReturned () {List fruits = Arrays.asList ("Appel", "Druiven", "Aardbeien"); assertEquals (fruits, groceryCart.get ("Fruits")); } @Test openbare leegte gegevenMultiValuedMap_whenVeggiesFetched_thenVeggiesReturned () {List veggies = Arrays.asList ("Spinazie", "Kool"); assertEquals (veggies, groceryCart.get ("Groenten")); } 

Bovendien, MultiMap geeft ons de mogelijkheid om een ​​bepaald item of een hele reeks waarden van de kaart te verwijderen:

@Test openbare leegte gegevenMultiValuedMap_whenFuitsRemoved_thenVeggiesPreserved () {assertEquals (5, groceryCart.size ()); groceryCart.remove ("Fruit", "Appel"); assertEquals (4, groceryCart.size ()); groceryCart.removeAll ("Fruit"); assertEquals (2, groceryCart.size ()); }

Zoals we kunnen zien, hebben we hier eerst verwijderd appel van de Fruit set en verwijderde vervolgens het geheel Fruit set.

5.2. Apache's MultiValuedMap

Nogmaals, laten we beginnen met het instantiëren van een MultiValuedMap:

MultiValuedMap groceryCart = nieuwe ArrayListValuedHashMap ();

Omdat het vullen hetzelfde is als we in de vorige sectie hebben gezien, laten we snel naar het gebruik kijken:

@Test openbare leegte gegevenMultiValuedMap_whenFruitsFetched_thenFruitsReturned () {List fruits = Arrays.asList ("Apple", "Grapes", "Strawberries"); assertEquals (fruits, groceryCart.get ("Fruits")); } @Test openbare leegte gegevenMultiValuedMap_whenVeggiesFetched_thenVeggiesReturned () {List veggies = Arrays.asList ("Spinazie", "Kool"); assertEquals (veggies, groceryCart.get ("Groenten")); }

Zoals we kunnen zien, is het gebruik ook hetzelfde!

In dit geval hebben we echter niet de flexibiliteit om een ​​enkele vermelding te verwijderen, zoals appel van Fruit.We kunnen alleen de hele set Fruit:

@Test openbare leegte gegevenMultiValuedMap_whenFuitsRemoved_thenVeggiesPreserved () {assertEquals (5, groceryCart.size ()); groceryCart.remove ("Fruit"); assertEquals (2, groceryCart.size ()); }

6. Wijs meerdere sleutels toe aan één waarde

Hier nemen we een voorbeeld van breedtegraden en lengtegraden die worden toegewezen aan de respectieve steden:

cityCoordinates.put ("40.7128 ° N", "74.0060 ° W", "New York"); cityCoordinates.put ("48.8566 ° N", "2.3522 ° E", "Parijs"); cityCoordinates.put ("19.0760 ° N", "72.8777 ° E", "Mumbai");

Nu zullen we zien hoe we dit kunnen bereiken.

6.1. Guava's Tafel

Guava biedt zijn Tafel die voldoet aan de bovenstaande use case:

Tabel cityCoordinates = HashBasedTable.create ();

En hier zijn enkele toepassingen die we eraan kunnen ontlenen:

@Test openbare leegte gegevenCoordinatesTable_whenFetched_thenOK () {Lijst verwachteLongitudes = Arrays.asList ("74.0060 ° W", "2.3522 ° E", "72.8777 ° E"); assertArrayEquals (verwachteLongitudes.toArray (), cityCoordinates.columnKeySet (). toArray ()); Lijst verwachteCities = Arrays.asList ("New York", "Parijs", "Mumbai"); assertArrayEquals (verwachteCities.toArray (), cityCoordinates.values ​​(). toArray ()); assertTrue (cityCoordinates.rowKeySet (). bevat ("48.8566 ° N")); }

Zoals we kunnen zien, kunnen we een Set weergave van de rijen, kolommen en waarden.

Tafel biedt ons ook de mogelijkheid om de rijen of kolommen te doorzoeken.

Laten we eens kijken naar een filmtafel om dit te demonstreren:

Tafelfilms = HashBasedTable.create (); movies.put ("Tom Hanks", "Meg Ryan", "You've Got Mail"); movies.put ("Tom Hanks", "Catherine Zeta-Jones", "The Terminal"); movies.put ("Bradley Cooper", "Lady Gaga", "A Star is Born"); movies.put ("Keenu Reaves", "Sandra Bullock", "Speed"); movies.put ("Tom Hanks", "Sandra Bullock", "Extreem luid en ongelooflijk dichtbij");

En hier zijn enkele voorbeelden van, voor zichzelf sprekende zoekopdrachten die we kunnen doen op onze filmsTafel:

@Test openbare leegte gegevenMoviesTable_whenFetched_thenOK () {assertEquals (3, movies.row ("Tom Hanks"). Size ()); assertEquals (2, movies.column ("Sandra Bullock"). size ()); assertEquals ("A Star is Born", movies.get ("Bradley Cooper", "Lady Gaga")); assertTrue (movies.containsValue ("Speed")); }

Echter, Tafel beperkt ons tot het toewijzen van slechts twee sleutels aan een waarde. We hebben nog geen alternatief in Guava om meer dan twee sleutels aan een enkele waarde toe te wijzen.

6.2. Apache's MultiKeyMap

Terugkomend op onze cityCoördinaten Dit is bijvoorbeeld hoe we het kunnen manipuleren met MultiKeyMap:

@Test openbare ongeldige gegevenCoordinatesMultiKeyMap_whenQueried_thenOK () {MultiKeyMap cityCoordinates = nieuwe MultiKeyMap (); // vul aan met sleutels en waarden zoals eerder getoond Lijst verwachteLongitudes = Arrays.asList ("72.8777 ° E", "2.3522 ° E", "74.0060 ° W"); Lijst lengtes = nieuwe ArrayList (); cityCoordinates.forEach ((sleutel, waarde) -> {longitudes.add (key.getKey (1));}); assertArrayEquals (verwachteLongitudes.toArray (), longitudes.toArray ()); Lijst verwachteCities = Arrays.asList ("Mumbai", "Parijs", "New York"); Lijst met steden = nieuwe ArrayList (); cityCoordinates.forEach ((sleutel, waarde) -> {cities.add (waarde);}); assertArrayEquals (verwachteCities.toArray (), steden.toArray ()); }

Zoals we kunnen zien aan de hand van het bovenstaande codefragment, komen we tot dezelfde beweringen als voor Guava's Tafel, we moesten herhalen over de MultiKeyMap.

Echter, MultiKeyMap biedt ook de mogelijkheid om meer dan twee sleutels aan een waarde toe te wijzen. Het geeft ons bijvoorbeeld de mogelijkheid om dagen van de week in kaart te brengen als weekdagen of weekenden:

@Test openbare ongeldige gegevenDaysMultiKeyMap_whenFetched_thenOK () {dagen = nieuwe MultiKeyMap (); days.put ("maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "weekdag"); days.put ("zaterdag", "zondag", "weekend"); assertFalse (days.get ("Saturday", "Sunday"). equals ("Weekday")); }

7. Apache Commons-collecties versus Google Guava

Volgens zijn ingenieurs, Google Guava is ontstaan ​​uit de behoefte om generieke geneesmiddelen in de bibliotheek te gebruiken, die Apache Commons niet bood. Het volgt ook de API-vereisten van de collecties tot in de puntjes. Een ander groot voordeel is dat het in actieve ontwikkeling is en dat er regelmatig nieuwe releases uitkomen.

Apache biedt echter een voorsprong als het gaat om prestaties bij het ophalen van een waarde uit een verzameling. Guava is echter nog steeds de kroon, in termen van inbrengtijden.

Hoewel we alleen de verzamelings-API's in onze codevoorbeelden vergeleken, Apache Commons als geheel biedt een veel groter scala aan functies in vergelijking met Guava.

8. Conclusie

In deze tutorial hebben we een deel van de functionaliteit die wordt aangeboden door Apache Commons en Google Guava vergeleken, met name op het gebied van het verzamelingsraamwerk.

Hier hebben we alleen maar de oppervlakte bekrast van wat de twee bibliotheken te bieden hebben.

Bovendien is het geen of-of-vergelijking. Zoals onze codevoorbeelden hebben aangetoond, er zijn kenmerken die uniek zijn voor elk van de twee, en er kunnen situaties zijn waarin beide naast elkaar kunnen bestaan.

Zoals altijd is de broncode beschikbaar op GitHub.


$config[zx-auto] not found$config[zx-overlay] not found