Apache Commons Collections vs Google Guava

1. 개요

이 튜토리얼에서는 Apache Commons와 Google Guava의 두 가지 Java 기반 오픈 소스 라이브러리를 비교 합니다. 두 라이브러리에는 주로 컬렉션 및 I / O 영역에 많은 유틸리티 API가 포함 된 풍부한 기능 세트가 있습니다.

간결함을 위해 여기서는 컬렉션 프레임 워크에서 가장 일반적으로 사용되는 몇 가지 코드 샘플과 함께 설명하겠습니다. 차이점에 대한 요약도 볼 수 있습니다.

또한 다양한 공유지 및 Guava 유틸리티에 대한 심층 분석을위한 기사 모음이 있습니다 .

2. 두 도서관의 간략한 역사

Google Guava는 현재는 오픈 소스이지만 주로 조직의 엔지니어가 개발 한 Google 프로젝트입니다. 이를 시작하게주요 동기는 JDK 1.5에 도입 된 제네릭을 Java Collections Framework 또는 JCF에 포함시키고 그 기능을 향상시키는 것이 었습니다 .

처음부터 라이브러리는 기능을 확장했으며 이제 그래프, 함수 프로그래밍, 범위 객체, 캐싱 및 문자열 조작을 포함합니다.

Apache Commons는 핵심 Java 컬렉션 API를 보완하기위한 Jakarta 프로젝트로 시작하여 결국 Apache Software Foundation의 프로젝트가되었습니다. 수년에 걸쳐 이미징, I / O, 암호화, 캐싱, 네트워킹, 유효성 검사 및 개체 풀링을 포함하여 (이에 국한되지 않음) 다양한 다른 영역에서 재사용 가능한 Java 구성 요소의 방대한 레퍼토리로 확장되었습니다.

이것은 오픈 소스 프로젝트이기 때문에 Apache 커뮤니티의 개발자는이 라이브러리에 계속 추가하여 기능을 확장합니다. 그러나 이전 버전과의 호환성을 유지하기 위해 세심한주의를 기울 입니다.

3. Maven 종속성

Guava를 포함하려면 해당 종속성을 pom.xml 에 추가해야합니다 .

 com.google.guava guava 29.0-jre 

최신 버전 정보는 Maven에서 찾을 수 있습니다.

Apache Commons의 경우 약간 다릅니다. 사용하고자하는 유틸리티에 따라 특정 유틸리티를 추가해야합니다. 예를 들어 컬렉션의 경우 다음을 추가해야합니다.

 org.apache.commons commons-collections4 4.4 

코드 샘플에서는 commons-collections4를 사용 합니다.

이제 재미있는 부분으로 뛰어 드세요!

4. 양방향지도

키와 값으로 액세스 할 수있는 맵을 양방향 맵이라고합니다. JCF에는이 기능이 없습니다.

두 기술이 어떻게 제공하는지 살펴 보겠습니다. 두 경우 모두 요일의 예를 사용하여 번호가 지정된 요일의 이름을 가져 오며 그 반대의 경우도 마찬가지입니다.

4.1. 구아바의 BiMap

Guava는 양방향지도로 BiMap 인터페이스를 제공합니다 . EnumBiMap , EnumHashBiMap , HashBiMap 또는 ImmutableBiMap 구현 중 하나로 인스턴스화 할 수 있습니다 .

여기서 우리는 HashBiMap을 사용 하고 있습니다 .

BiMap daysOfWeek = HashBiMap.create();

채우기는 Java의 모든 맵과 유사합니다.

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");

그리고 개념을 증명하기위한 몇 가지 JUnit 테스트가 있습니다.

@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. Apache의 BidiMap

마찬가지로 Apache는 BidiMap 인터페이스를 제공합니다 .

BidiMap daysOfWeek = new TreeBidiMap();

여기에서는 TreeBidiMap을 사용 합니다 . 그러나 DualHashBidiMapDualTreeBidiMap 과 같은 다른 구현 도 있습니다 .

이를 채우기 위해 위의 BiMap에서 했던 것처럼 값을 입력 할 수 있습니다 .

사용법도 매우 비슷합니다.

@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)); }

몇 가지 간단한 성능 테스트에서이 양방향 맵 은 삽입에서만 Guava 대응보다 뒤처졌습니다. 키와 값을 가져 오는 데 훨씬 더 빠릅니다 .

5. 여러 값에 키 매핑

과일 및 채소 용 식료품 카트 컬렉션과 같이 여러 키를 서로 다른 값에 매핑하려는 사용 사례의 경우 두 라이브러리가 고유 한 솔루션을 제공합니다.

5.1. 구아바의 멀티 맵

먼저 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");

그런 다음 몇 가지 JUnit 테스트를 사용하여 실제로 작동하는지 확인합니다.

@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.

여기서 우리는 두 라이브러리가 제공해야하는 것의 표면을 긁어봤을뿐입니다.

더욱이 그것은 둘 중 하나 또는 비교가 아닙니다. 코드 샘플에서 설명했듯이 두 가지 각각에 고유 한 기능이 있으며 둘 다 공존 할 수있는 상황이있을 수 있습니다 .

항상 그렇듯이 소스 코드는 GitHub에서 사용할 수 있습니다.