Collection Enhancements in Google Guava

Guava library introduces many utility methods for collections as well as new types of collections to be used in various programming scenarios.

Immutable Collections:

Even though JDK provides immutable collections through Collections.unmodifiableList, unmodifiableSet etc, they are not very efficient as they go through all the operations which exist in a normal collection.

Initializing Immutables is done with of method where individual elements are passed as parameters or copyOf method where an Iterable can be passed as a parameter. It can even be initialized using a Builder where multiple elements can be added on the fly to build an Immutable collection.

ImmutableSet<String> set = ImmutableSet.of("a", "b", "c", "b");
ImmutableSet<String> set2 = ImmutableSet.copyOf(set);

ImmutableList<String> list = set.asList();

ImmutableMap<String, Integer> map = ImmutableMap.of("a", 1, "b", 2, "c", 3);

ImmutableList<String> list2 = ImmutableList.<String>builder().add("a", "b", "c").build();

New Collection Types:

  • MultiSet – This is a collection which¬† accepts the same value multiple times and stores it as the element against the number of occurrences it is being added to the collection. The number of occurrences for a given element can be obtained using the count() method.
Multiset<String> multiset = HashMultiset.create();
multiset.add("A");
multiset.add("A"); // accepted, count of "A"'s occurrence increases by 1.
multiset.count("A");// returns 2
  • MultiMap – Like MultiSet, this accepts multiple values for a single key. The data is stored as a single key with a List of values. A real life example of its application can be with HTTP headers where same header name can be associated with multiple values.
    Multimap<String, String> multimap = ArrayListMultimap.create();
    multimap.put("A", "one");
    multimap.put("A", "two");//accept, does not replace "one", stored as one more mapping.
    System.out.println(multimap.get("A")); //prints ["one", "two"]

    Caution should be exercised while using this as multimap.get() will never return a null, if the value does not exist, the return is an empty List to which a value can be added. In order to check existence of a key, it can be done in two ways.

    multimap.get("B").size==0;// key does not exist as no mapping exists
    multimap.asMap().get("B")==null; // asMap gives the equivalent representation of java.util.Map

keys() method can be used to get the keys as a MultiSet with key as the entry and number of values in the map representing the value of MultiSet.

multimap.keys().count("A"); // returns 2

entries() method returns each of the key-value pairs.

multimap.entries(); // returns A:1, A:2 as separate entries
multimap.asMap().entries(); // returns A:[1, 2] as single entry

clear() method can be used to evict a key from the MultiMap. As MultiMap does not allow an entry without values, the key is naturally out of the collection when all the values are cleared.

  • BiMapBiMap is a special collection which finds its use in multiple programming scenarios. BiMap accepts entries where both keys and values are restricted to be unique. With such unique association, it provides an inverse() method which can be invoked to have all the values as keys and keys as values, thus supporting a reverse lookup functionality. With this collection, it is always easy to maintain two way mapping, without having to manually maintain two separate maps which can lead to data inconsistency.
BiMap<String, Integer> biMap = HashBiMap.create();
biMap.put("a", "1");
biMap.get("a"); // returns "1"
biMap.inverse().get("1"); // returns "a"
  • TableTable is a collection which is used to maintain a tabular mapping of the information. With this, it is easy to maintain a mapping of data where a row and a column can contain a specific value. Real life examples would include a school time table, sudoku chart etc.
    Table<String, Integer, String> table = HashBasedTable.create();
    table.put("Monday", 1, "Language1");
    table.put("Monday", 2, "Maths");
    table.put("Tuesday", 1, "Science");
    
    System.out.println(table); //{Monday={1=Language1, 2=Maths}, Tuesday={1=Science}}
    System.out.println(table.row("Monday")); //{1=Language1, 2=Maths}
    System.out.println(table.column(1)); //{Monday=Language1, Tuesday=Science}
    System.out.println(table.columnKeySet()); // [1, 2]
    System.out.println(table.get("Monday", 2)); // Maths

    ClassToInstanceMap – This can be used in factories that provide singleton objects for a given class. A class instance can be initialized once and stored in this collection and be used readily. Primarily this is a Map, but it has getInstance and putInstance methods which can reduce type casting effort.

    ClassToInstanceMap instanceMap = MutableClassToInstanceMap.create();
    List<String> list = new ArrayList<>();
    instanceMap.putInstance(List.class, list);
    System.out.println(list == instanceMap.getInstance(List.class));

    Apart from these, few new collections related to numerical ranges exist, whose real life application seems to be limited.