Koleksi Apache Commons vs Google Jambu

1. Gambaran keseluruhan

Dalam tutorial ini, kita akan membandingkan dua perpustakaan sumber terbuka berasaskan Java: Apache Commons dan Google Guava . Kedua-dua perpustakaan mempunyai set fitur yang kaya dengan banyak API utiliti terutama di koleksi dan kawasan I / O.

Untuk kesimpulan, di sini kita hanya akan menerangkan sebilangan kecil yang paling biasa digunakan dari kerangka koleksi bersama dengan contoh kod. Kami juga akan melihat ringkasan perbezaan mereka.

Selain itu, kami mempunyai koleksi artikel untuk menyelami pelbagai utiliti umum dan Jambu batu .

2. Sejarah Ringkas Dua Perpustakaan

Jambu batu Google adalah projek Google, yang dibangunkan terutamanya oleh jurutera organisasi, walaupun kini telah bersumber terbuka. The motivasi utama untuk memulakannya adalah untuk memasukkan generik diperkenalkan pada JDK 1.5 ke dalam Rangka Kerja Collections Java , atau JCF, dan meningkatkan keupayaannya.

Sejak penubuhannya, perpustakaan telah memperluas kemampuannya dan sekarang termasuk grafik, pengaturcaraan fungsional, objek jarak, caching, dan manipulasi String .

Apache Commons dimulakan sebagai proyek Jakarta untuk melengkapi API inti koleksi Java dan akhirnya menjadi projek Yayasan Perisian Apache. Selama bertahun-tahun, ini telah berkembang menjadi repertoar komponen Java yang dapat digunakan kembali di berbagai bidang lain, termasuk (tetapi tidak terbatas pada) pencitraan, I / O, kriptografi, caching, rangkaian, pengesahan, dan penyatuan objek.

Oleh kerana ini adalah projek sumber terbuka, pemaju dari komuniti Apache terus menambah ke perpustakaan ini untuk mengembangkan kemampuannya. Walau bagaimanapun, mereka sangat berhati-hati untuk mengekalkan keserasian ke belakang .

3. Ketergantungan Maven

Untuk memasukkan Jambu Batu, kita perlu menambahkan kebergantungannya ke pom.xml kami :

 com.google.guava guava 29.0-jre 

Maklumat versi terbaru boleh didapati di Maven.

Bagi Apache Commons, ia sedikit berbeza. Bergantung pada utiliti yang ingin kita gunakan, kita harus menambahkan yang khusus. Sebagai contoh, untuk koleksi, kita perlu menambah:

 org.apache.commons commons-collections4 4.4 

Dalam contoh kod kami, kami akan menggunakan koleksi-commons4 .

Mari lompat ke bahagian yang menyeronokkan sekarang!

4. Peta Dua Hala

Peta yang dapat diakses dengan kunci, serta nilai, dikenal sebagai peta dua arah. JCF tidak mempunyai ciri ini.

Mari lihat bagaimana kedua teknologi kami menawarkannya. Dalam kedua kes tersebut, kami akan mengambil contoh hari dalam seminggu untuk mendapatkan nama hari memandangkan bilangannya dan sebaliknya.

4.1. BiMap Jambu Batu

Jambu biji menawarkan antara muka - BiMap , sebagai peta dua arah. Ia dapat dibentuk dengan salah satu implementasinya EnumBiMap , EnumHashBiMap , HashBiMap , atau ImmutableBiMap .

Di sini kita menggunakan HashBiMap :

BiMap daysOfWeek = HashBiMap.create();

Mengisinya serupa dengan peta di Jawa:

daysOfWeek.put(1, "Monday"); daysOfWeek.put(2, "Tuesday"); daysOfWeek.put(3, "Wednesday"); daysOfWeek.put(4, "Thursday"); daysOfWeek.put(5, "Friday"); daysOfWeek.put(6, "Saturday"); daysOfWeek.put(7, "Sunday");

Dan berikut adalah beberapa ujian JUnit untuk membuktikan konsepnya:

@Test public void givenBiMap_whenValue_thenKeyReturned() { assertEquals(Integer.valueOf(7), daysOfWeek.inverse().get("Sunday")); } @Test public void givenBiMap_whenKey_thenValueReturned() { assertEquals("Tuesday", daysOfWeek.get(2)); }

4.2. Peta Bidi Apache

Begitu juga, Apache menyediakan antara muka BidiMap kami :

BidiMap daysOfWeek = new TreeBidiMap();

Di sini kita menggunakan TreeBidiMap . Walau bagaimanapun, terdapat implementasi lain, seperti DualHashBidiMap dan DualTreeBidiMap juga .

To populate it, we can put the values as we did for BiMap above.

Its usage is also pretty similar:

@Test public void givenBidiMap_whenValue_thenKeyReturned() { assertEquals(Integer.valueOf(7), daysOfWeek.inverseBidiMap().get("Sunday")); } @Test public void givenBidiMap_whenKey_thenValueReturned() { assertEquals("Tuesday", daysOfWeek.get(2)); }

In a few simple performance tests, this bi-directional map lagged behind its Guava counterpart only in insertions. It was much faster in fetching keys as well as values.

5. Map Keys to Multiple Values

For a use case where we'd want to map multiple keys to different values, such as a grocery cart collection for fruits and vegetables, the two libraries offer us unique solutions.

5.1. Guava's MultiMap

First, let's see how to instantiate and initialize MultiMap:

Multimap groceryCart = ArrayListMultimap.create(); groceryCart.put("Fruits", "Apple"); groceryCart.put("Fruits", "Grapes"); groceryCart.put("Fruits", "Strawberries"); groceryCart.put("Vegetables", "Spinach"); groceryCart.put("Vegetables", "Cabbage");

Then, we'll use a couple of JUnit tests to see it in action:

@Test public void givenMultiValuedMap_whenFruitsFetched_thenFruitsReturned() { List fruits = Arrays.asList("Apple", "Grapes", "Strawberries"); assertEquals(fruits, groceryCart.get("Fruits")); } @Test public void givenMultiValuedMap_whenVeggiesFetched_thenVeggiesReturned() { List veggies = Arrays.asList("Spinach", "Cabbage"); assertEquals(veggies, groceryCart.get("Vegetables")); } 

Additionally, MultiMap gives us the ability to remove a given entry or an entire set of values from the map:

@Test public void givenMultiValuedMap_whenFuitsRemoved_thenVeggiesPreserved() { assertEquals(5, groceryCart.size()); groceryCart.remove("Fruits", "Apple"); assertEquals(4, groceryCart.size()); groceryCart.removeAll("Fruits"); assertEquals(2, groceryCart.size()); }

As we can see, here we first removed Apple from the Fruits set and then removed the entire Fruits set.

5.2. Apache's MultiValuedMap

Again, let's begin with instantiating a MultiValuedMap:

MultiValuedMap groceryCart = new ArrayListValuedHashMap();

Since populating it is the same as we saw in the previous section, let's quickly look at the usage:

@Test public void givenMultiValuedMap_whenFruitsFetched_thenFruitsReturned() { List fruits = Arrays.asList("Apple", "Grapes", "Strawberries"); assertEquals(fruits, groceryCart.get("Fruits")); } @Test public void givenMultiValuedMap_whenVeggiesFetched_thenVeggiesReturned() { List veggies = Arrays.asList("Spinach", "Cabbage"); assertEquals(veggies, groceryCart.get("Vegetables")); }

As we can see, its usage is also the same!

However, in this case, we don't have the flexibility to remove a single entry, such as Apple from Fruits.We can only remove the entire set of Fruits:

@Test public void givenMultiValuedMap_whenFuitsRemoved_thenVeggiesPreserved() { assertEquals(5, groceryCart.size()); groceryCart.remove("Fruits"); assertEquals(2, groceryCart.size()); }

6. Map Multiple Keys to One Value

Here, we'll take an example of latitudes and longitudes to be mapped to respective cities:

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

Now, we'll see how to achieve this.

6.1. Guava's Table

Guava offers its Table that satisfies the above use case:

Table cityCoordinates = HashBasedTable.create();

And here are some usages we can derive out of it:

@Test public void givenCoordinatesTable_whenFetched_thenOK() { List expectedLongitudes = Arrays.asList("74.0060° W", "2.3522° E", "72.8777° E"); assertArrayEquals(expectedLongitudes.toArray(), cityCoordinates.columnKeySet().toArray()); List expectedCities = Arrays.asList("New York", "Paris", "Mumbai"); assertArrayEquals(expectedCities.toArray(), cityCoordinates.values().toArray()); assertTrue(cityCoordinates.rowKeySet().contains("48.8566° N")); }

As we can see, we can get a Set view of the rows, columns, and values.

Table also offers us the ability to query its rows or columns.

Let's consider a movie table to demonstrate this:

Table movies = 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", "Extremely Loud & Incredibly Close");

And here are some sample, self-explanatory searches that we can do on our moviesTable:

@Test public void givenMoviesTable_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")); }

However, Table limits us to map only two keys to a value. We don't have an alternative as yet in Guava to map more than two keys to a single value.

6.2. Apache's MultiKeyMap

Coming back to our cityCoordinates example, here's how we can manipulate it using MultiKeyMap:

@Test public void givenCoordinatesMultiKeyMap_whenQueried_thenOK() { MultiKeyMap cityCoordinates = new MultiKeyMap(); // populate with keys and values as shown previously List expectedLongitudes = Arrays.asList("72.8777° E", "2.3522° E", "74.0060° W"); List longitudes = new ArrayList(); cityCoordinates.forEach((key, value) -> { longitudes.add(key.getKey(1)); }); assertArrayEquals(expectedLongitudes.toArray(), longitudes.toArray()); List expectedCities = Arrays.asList("Mumbai", "Paris", "New York"); List cities = new ArrayList(); cityCoordinates.forEach((key, value) -> { cities.add(value); }); assertArrayEquals(expectedCities.toArray(), cities.toArray()); }

As we can see from the above code snippet, to arrive at the same assertions as for Guava's Table, we had to iterate over the MultiKeyMap.

However, MultiKeyMap also offers the possibility to map more than two keys to a value. For example, it gives us the ability to map days of the week as weekdays or weekends:

@Test public void givenDaysMultiKeyMap_whenFetched_thenOK() { days = new MultiKeyMap(); days.put("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Weekday"); days.put("Saturday", "Sunday", "Weekend"); assertFalse(days.get("Saturday", "Sunday").equals("Weekday")); }

7. Apache Commons Collections vs. Google Guava

As per its engineers, Google Guava was born out of the need to use generics in the library, which Apache Commons didn't offer. It also follows the collections API requirements to the tee. Another major advantage is that it's in active development with new releases coming out frequently.

However, Apache offers an edge when it comes to performance while fetching a value from a collection. Guava still takes the cake though, in terms of insertion times.

Although we compared only the collections APIs in our code samples, Apache Commons as a whole offers a much bigger gamut of features as compared to Guava.

8. Conclusion

In this tutorial, we compared some of the functionality offered by Apache Commons and Google Guava, specifically in the area of the collections framework.

Di sini, kami hanya menggaru permukaan apa yang ditawarkan oleh kedua perpustakaan.

Lebih-lebih lagi, ini bukan perbandingan atau perbandingan Seperti yang ditunjukkan oleh contoh kod kami, terdapat ciri-ciri yang unik untuk kedua-duanya, dan ada situasi di mana keduanya dapat wujud bersama .

Seperti biasa, kod sumber tersedia di GitHub.