1. Introduction
When using Map in daily development, we often encounter many complex processing scenarios, such as: Map with multiple keys, not only the value can be obtained based on the key, but also the key can be obtained based on the value without traversing, Map with repeated keys, numbers and other ranges Mapping the same value internally, caching objects in memory, etc. Guava provides solutions to the above scenarios.
Scenario | Solution | Specific implementation |
---|---|---|
Map with multiple keys | Table | HashBasedTable, TreeBasedTable, ImmutableTable |
Not only can the value be obtained based on the key, but also the value can be obtained based on the key. Get the key by value without traversing | BiMap | HashBiMap, ImmutableBiMap |
Map of repeated keys | Multimap | ArrayListMultimap, LinkedListMultimap, LinkedHashMultimap, ImmutableListMultimap, ImmutableSetMultimap |
Map the same value within the range of numbers | RangeMap | TreeRangeMap, ImmutableRangeMap |
Cache objects in memory | ClassToInstanceMap | MutableClassToInstanceMap, ImmutableClassToInstanceMap |
This blog will describe the specific sample code in detail.
2. Add dependencies
Add dependencies in Maven project pom.xml:
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>32.0.0-jre</version> </dependency>
3. Tbale – table structure data
Official comment translation: A collection that associates a pair of ordered keys (called a row key and a column key) with a single value.
Sample code (Requirement: record the number of people in each department of each company):
// HashMap Map<String, Integer> deptMap = new HashMap<>(); deptMap.put("Department A", 10); deptMap.put("Department B", 20); Map<String, Map<String, Integer>> companyMap = new HashMap<>(); companyMap.put("xx company", deptMap); // HashMap gets value Integer val = companyMap.get("xx company").get("Department A"); System.out.println("HashMap gets value: " + val); // Create Hash type Table, implemented based on Hash table //Three generics in Table<R, C, V>: R-row, C-column, V-value Table<String, String, Integer> hashTable = HashBasedTable.create(); hashTable.put("xx company", "A department", 10); hashTable.put("xx company", "B department", 20); hashTable.put("xx company", "C department", 30); System.out.println("\\ Hash Table: " + hashTable); //Create a Tree type Table, implemented based on red-black tree Table<String, String, Integer> treeTable = TreeBasedTable.create(); treeTable.put("xx company", "C department", 30); treeTable.put("xx company", "B department", 20); treeTable.put("xx company", "A department", 10); System.out.println("\\ Tree Table: " + treeTable); //Create an immutable Table, which cannot be added, updated or deleted Table<String, String, Integer> immutableTable = ImmutableTable.<String, String, Integer>builder() .put("xx company", "C department", 30) .put("xx company", "B department", 20) .put("xx company", "A department", 10) .build(); System.out.println("\\ Immutable Table: " + immutableTable); // Table gets value Integer val2 = hashTable.get("xx company", "A department"); System.out.println("\\ Table get value: " + val2); //Table delete value Integer remove = hashTable.remove("xx company", "C department"); System.out.println("\\ Table delete value: " + remove); // Get column and value mapping based on row Map<String, Integer> columnvalueMap = hashTable.row("xx company"); System.out.println("\\ Table column and value mapping: " + columnvalueMap); // Get row and value mapping based on column Map<String, Integer> rowvalueMap = hashTable.column("Department A"); System.out.println("\\ Table row and value mapping: " + rowvalueMap); // Get the key collection Set<String> rowKeySet = hashTable.rowKeySet(); System.out.println("\\ Table Row key set: " + rowKeySet); Set<String> columnKeySet = hashTable.columnKeySet(); System.out.println("\\ Table Column key set: " + columnKeySet); // Get value collection Collection<Integer> values = hashTable.values(); System.out.println("\\ Table value collection: " + values); // Determine containing rows boolean containsRow = hashTable.containsRow("xx company"); System.out.println("\\ Table contains rows: " + containsRow); // Determine the included columns boolean containsColumn = hashTable.containsColumn("Department A"); System.out.println("\\ Table contains columns: " + containsColumn); // Determine whether rows and columns are included boolean contains = hashTable.contains("xx company", "A department"); System.out.println("\\ Table contains rows and columns: " + contains); // Determine the value contained boolean containsValue = hashTable.containsValue(10); System.out.println("\\ Table contains value: " + containsValue); // Row and column transpose - row to column Table<String, String, Integer> transposeTable = Tables.transpose(hashTable); // Get all rows Set<Table.Cell<String, String, Integer>> cells = transposeTable.cellSet(); //Loop through the output System.out.println("\\ Traverse output starts-------------------------------"); cells.forEach(cell -> System.out.println(cell.getRowKey() + ", " + cell.getColumnKey() + ", " + cell.getValue())); System.out.println("\\ End of traversal output-------------------------------"); //Convert to nested Map Map<String, Map<String, Integer>> rowMap = hashTable.rowMap(); System.out.println("\\ Table RowMap: " + rowMap); Map<String, Map<String, Integer>> columnMap = hashTable.columnMap(); System.out.println("\\ Table ColumnMap: " + columnMap);
Results of the:
HashMap gets value: 10 Hash Table: {xx company={Department A=10, Department B=20, Department C=30}} Tree Table: {xx company={Department A=10, Department B=20, Department C=30}} Immutable Table: {xx company={Department C=30, Department B=20, Department A=10}} Table gets value: 10 Table delete value: 30 Table column and value mapping: {Department A=10, Department B=20} Table row and value mapping: {xx company=10} Table Row key collection: [xx company] Table Column key collection: [Department A, Department B] Table value collection: [10, 20] Table contains rows: true Table contains columns: true Table contains rows and columns: true Table contains values: true Traversal output starts--------------------------- Department A, Company xx, 10 Department B, xx company, 20 End of traversal output--------------------------- Table RowMap: {xx company={Department A=10, Department B=20}} Table ColumnMap: {A department={xx company=10}, B department={xx company=20}}
4. BiMap – bidirectional mapping Map
Official Note Translation: A bimap (or “bidirectional map”) is a map that preserves the uniqueness of its values and its keys. This constraint enables a double map to support a “reverse view”, that is, another double map containing the same entries as this double map, but with opposite keys and values.
Sample code (Requirements: array and English translation):
// Create BiMap, the bottom layer is a Map of two Hash tables BiMap<Integer, String> biMap = HashBiMap.create(); biMap.put(1, "one"); biMap.put(2, "two"); biMap.put(3, "three"); biMap.put(4, "four"); biMap.put(5, "five"); System.out.println("BiMap: " + biMap); //Create an immutable BiMap, which cannot be added, updated or deleted. BiMap<Object, Object> immutableBiMap = ImmutableBiMap.builder() .put(1, "one") .put(2, "two") .put(3, "three") .put(4, "four") .put(5, "five") .build(); System.out.println("\\ Immutable BiMap: " + immutableBiMap); // Get value through key String value = biMap.get(1); System.out.println("\\ BiMap gets value based on key: " + value); Integer key = biMap.inverse().get("one"); System.out.println("\\ BiMap gets key based on value: " + key); //Modify after flipping biMap.inverse().put("six", 6); // Return the reverse view of the double mapping. No new object is created, it is still the previous object, so operating the flipped BiMap will affect the previous BiMap System.out.println("\\ BiMap is affected: " + biMap); //The bottom layer is HashMap, the key cannot be repeated // value cannot be repeated try { biMap.put(11, "one"); } catch (Exception e) { System.err.println("BiMap value replacement exception: " + e.getMessage()); } //The key cannot be repeated after flipping try { biMap.inverse().put("first", 1); } catch (Exception e) { System.err.println("BiMap key replacement exception: " + e.getMessage()); } // key and value can be null biMap.put(null, null); System.out.println("\\ BiMap gets Null value based on Null key: " + biMap.get(null)); System.out.println("\\ BiMap gets Null key based on Null value: " + biMap.inverse().get(null)); //Force replacement key biMap.forcePut(11, "one"); System.out.println("\\ BiMap gets new key: " + biMap.inverse().get("one")); // values are Set collection Set<String> values = biMap.values(); System.out.println("\\ BiMap unique value: " + values);
Results of the:
BiMap: {1=one, 2=two, 3=three, 4=four, 5=five} Immutable BiMap: {1=one, 2=two, 3=three, 4=four, 5=five} BiMap gets value based on key: one BiMap gets key based on value: 1 BiMap affected: {1=one, 2=two, 3=three, 4=four, 5=five, 6=six} BiMap replace value exception: value already present: one BiMap key replacement exception: key already present: 1 BiMap gets Null value based on Null key: null BiMap gets Null key based on Null value: null BiMap gets new key: 11 BiMap unique value: [two, three, four, five, six, null, one]
5. Multimap – Multiple mapping Map
Official Note Translation Maps keys to collections of values, similar to Map, but where each key may be associated with multiple values.
Sample code (Requirements: students and elective course scores in each subject):
// Create Multimap, key is HashMap, value is ArrayList Multimap<String, Integer> arrayListMultimap = ArrayListMultimap.create(); arrayListMultimap.put("Zhang San", 90); arrayListMultimap.put("Zhang San", 80); arrayListMultimap.put("Zhang San", 100); arrayListMultimap.put("李思", 88); System.out.println("Multimap key is HashMap, value is ArrayList: " + arrayListMultimap); //Create Multimap, key is HashMap, value is HashSet Multimap<String, Integer> hashMultimap = HashMultimap.create(); hashMultimap.put("Zhang San", 90); hashMultimap.put("Zhang San", 80); hashMultimap.put("Zhang San", 100); hashMultimap.put("李思", 88); System.out.println("\\ Multimap key is HashMap, value is HashSet: " + hashMultimap); // Create Multimap, key is LinkedHashMap, value is LinkedList Multimap<String, Integer> linkedListMultimap = LinkedListMultimap.create(); linkedListMultimap.put("Zhang San", 90); linkedListMultimap.put("Zhang San", 80); linkedListMultimap.put("Zhang San", 100); linkedListMultimap.put("李思", 88); System.out.println("\\ Multimap key is LinkedHashMap, value is LinkedList: " + linkedListMultimap); // Create Multimap, key is LinkedHashMap, value is LinkedHashMap Multimap<String, Integer> linkedHashMultimap = LinkedHashMultimap.create(); linkedHashMultimap.put("张三", 90); linkedHashMultimap.put("张三", 80); linkedHashMultimap.put("张三", 100); linkedHashMultimap.put("李思", 88); System.out.println("\\ Multimap key is LinkedHashMap, value is LinkedHashMap: " + linkedHashMultimap); //Create Multimap, key is TreeMap, value is TreeSet Multimap<String, Integer> treeMultimap = TreeMultimap.create(); treeMultimap.put("Zhang San", 90); treeMultimap.put("Zhang San", 80); treeMultimap.put("Zhang San", 100); treeMultimap.put("李思", 88); System.out.println("\\ Multimap key is TreeMap, value is TreeSet: " + treeMultimap); //Create an immutable Multimap, which cannot be added, updated or deleted. The key is ImmutableMap and the value is ImmutableList. Multimap<String, Integer> immutableListMultimap = ImmutableListMultimap.<String, Integer>builder() .put("Zhang San", 90) .put("Zhang San", 80) .put("Zhang San", 100) .put("李思", 88) .build(); System.out.println("\\ Multimap key is ImmutableMap, value is ImmutableList: " + immutableListMultimap); //Create an immutable Multimap, which cannot be added, updated or deleted. The key is ImmutableMap and the value is ImmutableSet. Multimap<String, Integer> immutableSetMultimap = ImmutableSetMultimap.<String, Integer>builder() .put("Zhang San", 90) .put("Zhang San", 80) .put("Zhang San", 100) .put("李思", 88) .build(); System.out.println("\\ Multimap key is ImmutableMap, value is ImmutableSet: " + immutableSetMultimap); // get value Collection<Integer> values = arrayListMultimap.get("Zhang San"); System.out.println("\\ Multimap gets the value set: " + values); // Get the value of the key that does not exist, and return an empty collection instead of null Collection<Integer> valuesByNotExistsKey = arrayListMultimap.get("王五"); System.out.println("\\ Multimap gets the non-existent Key value set: " + valuesByNotExistsKey); // Get value collection and add value // What is returned is the view collection of the values associated in the multimap. No new object is created, it is still the previous object, so the operation value collection will affect the previous Multimap values.add(60); System.out.println("\\ Multimap is affected: " + arrayListMultimap); // Get the size System.out.println("\\ Multimap size:" + arrayListMultimap.size()); // Determine whether it is empty System.out.println("\\ Multimap is empty: " + arrayListMultimap.isEmpty()); // Contains key System.out.println("\\ Multimap contains key: " + arrayListMultimap.containsKey("Zhang San")); // contains value System.out.println("\\ Multimap contains value: " + arrayListMultimap.containsValue(60)); // Contains key-value key-value pairs System.out.println("\\ Multimap contains key-value pairs: " + arrayListMultimap.containsEntry("Zhang San", 60)); //replace value arrayListMultimap.replaceValues("张三", Arrays.asList(10, 20, 30)); System.out.println("\\ Multimap replace value: " + arrayListMultimap); //Delete based on key-value arrayListMultimap.remove("Zhang San", 10); System.out.println("\\ Multimap delete based on key-value: " + arrayListMultimap); //Delete based on key Collection<Integer> removeAll = arrayListMultimap.removeAll("Zhang San"); System.out.println("\\ Multimap delete based on key: " + removeAll); // Get the key collection Set<String> keySet = arrayListMultimap.keySet(); System.out.println("\\ Multimap gets the key set (HashSet): " + keySet); Multiset<String> keys = arrayListMultimap.keys(); System.out.println("\\ Multimap gets the key set (MultiSet): " + keys); // Get all key-values Collection<Map.Entry<String, Integer>> entries = arrayListMultimap.entries(); System.out.println("\\ Start traversing key-value---------------------------"); entries.forEach(entry -> System.out.println(entry.getKey() + " : " + entry.getValue())); System.out.println("\\ End of key-value traversal--------------------------"); // Convert to Map<K, Collection<V>> Map<String, Collection<Integer>> collectionMap = arrayListMultimap.asMap(); System.out.println("\\ Multimap converted to Map<K, Collection<V>>: " + collectionMap);
Results of the:
Multimap key is HashMap, value is ArrayList: {李思=[88], Zhang San=[90, 80, 100]} Multimap key is HashMap, value is HashSet: {李思=[88], Zhang San=[80, 100, 90]} Multimap key is LinkedHashMap, value is LinkedList: {Zhang San=[90, 80, 100], Li Si=[88]} Multimap key is LinkedHashMap, value is LinkedHashMap: {Zhang San=[90, 80, 100], Li Si=[88]} Multimap key is TreeMap, value is TreeSet: {Zhang San=[80, 90, 100], Li Si=[88]} Multimap key is ImmutableMap, value is ImmutableList: {Zhang San=[90, 80, 100], Li Si=[88]} Multimap key is ImmutableMap, value is ImmutableSet: {Zhang San=[90, 80, 100], Li Si=[88]} Multimap gets the value set: [90, 80, 100] Multimap gets a non-existent Key value set: [] Multimap is affected: {李思=[88], Zhang San=[90, 80, 100, 60]} Multimap size:5 Whether Multimap is empty: false Multimap contains key: true Multimap contains value: true Multimap contains key-value pairs: true Multimap replace value: {李思=[88], Zhang San=[10, 20, 30]} Multimap delete based on key-value: {李思=[88], Zhang San=[20, 30]} Multimap delete based on key: [20, 30] Multimap gets the key set (HashSet): [李思] Multimap gets the key set (MultiSet): [李思] Start traversing key-value-------------------------- John Doe : 88 End of traversing key-value-------------------------- Multimap converted to Map<K, Collection<V>>: {李思=[88]}
6. RangeMap – range mapping Map
Official comment translation: Mapping from disjoint non-empty ranges to non-null values. The query finds the value associated with the range (if any) that contains the specified key.
Sample code (Requirement: Examination score classification):
// if-else int score = 88; String rank; if (0 <= score & amp; & amp; score < 60) { rank = "failed"; } else if (60 <= score & amp; & amp; score <= 84) { rank = "pass"; } else if (84 < score & amp; & amp; score <= 100) { rank = "Excellent"; } else { rank = "invalid"; } System.out.println("if-else get value: " + rank); // Create RangeMap, implemented based on TreeMap (red-black tree) RangeMap<Integer, String> treeRangeMap = TreeRangeMap.create(); treeRangeMap.put(Range.closedOpen(0, 60), "failed"); treeRangeMap.put(Range.closed(60, 84), "pass"); treeRangeMap.put(Range.openClosed(84, 100), "Excellent"); treeRangeMap.put(Range.lessThan(0), "invalid"); treeRangeMap.put(Range.greaterThan(100), "invalid"); rank = treeRangeMap.get(score); System.out.println("\\ RangeMap gets the value: " + rank); //Create an immutable RangeMap, which cannot be added, updated or deleted ImmutableRangeMap<Integer, String> immutableRangeMap = ImmutableRangeMap.<Integer, String>builder() .put(Range.closedOpen(0, 60), "failed") .put(Range.closed(60, 84), "pass") .put(Range.openClosed(84, 100), "Excellent") .put(Range.lessThan(0), "invalid") .put(Range.greaterThan(100), "invalid") .build(); rank = immutableRangeMap.get(score); System.out.println("\\ ImmutableRangeMap gets the value: " + rank); // Get the key-value pair Map.Entry<Range<Integer>, String> entry = treeRangeMap.getEntry(88); System.out.println("\\ RangeMap gets the key-value pair: " + entry.getKey() + " : " + entry.getValue()); // Return an immutable ascending Map Map<Range<Integer>, String> asMapOfRanges = treeRangeMap.asMapOfRanges(); System.out.println("\\ RangeMap immutable ascending Map: " + asMapOfRanges); // Return an immutable descending Map Map<Range<Integer>, String> asDescendingMapOfRanges = treeRangeMap.asDescendingMapOfRanges(); System.out.println("\\ RangeMap immutable descending Map: " + asDescendingMapOfRanges); // Merge connected ranges RangeMap<Integer, String> treeRangeMap2 = TreeRangeMap.create(); treeRangeMap2.putCoalescing(Range.closedOpen(0, 60), "failed"); treeRangeMap2.putCoalescing(Range.closed(60, 84), "passed"); treeRangeMap2.putCoalescing(Range.openClosed(84, 100), "pass"); // or [60..84] range merging treeRangeMap2.putCoalescing(Range.lessThan(0), "invalid"); treeRangeMap2.putCoalescing(Range.greaterThan(100), "invalid"); System.out.println("\\ RangeMap does not merge connected ranges: " + treeRangeMap.asMapOfRanges()); System.out.println("RangeMap merges connected ranges: " + treeRangeMap2.asMapOfRanges()); // minimum range Range<Integer> span = treeRangeMap.span(); System.out.println("\\ RangeMap minimum range: " + span); // Subrange Map RangeMap<Integer, String> subRangeMap = treeRangeMap.subRangeMap(Range.closed(70, 90)); System.out.println("\\ RangeMap subrangeMap: " + subRangeMap); //Merge range treeRangeMap.merge(Range.closed(60, 100), "passed", (s, s2) -> s2); System.out.println("\\ RangeMap merge Map: " + treeRangeMap); // remove range treeRangeMap.remove(Range.open(90, 95)); System.out.println("\\ RangeMap remove range: " + treeRangeMap); // Clear all ranges treeRangeMap.clear(); System.out.println("\\ RangeMap clears all ranges: " + treeRangeMap);
Results of the:
if-else gets value: excellent RangeMap gets value: Excellent ImmutableRangeMap gets value: excellent RangeMap obtains key-value pairs: (84..100]: Excellent RangeMap immutable ascending map: {(-∞..0)=invalid, [0..60)=fail, [60..84]=pass, (84..100]=excellent, (100. . + ∞)=invalid} RangeMap immutable descending map: {(100.. + ∞)=invalid, (84..100]=excellent, [60..84]=passing, [0..60)=failed, (-∞ ..0)=invalid} RangeMap does not merge connected ranges: {(-∞..0)=invalid, [0..60)=fail, [60..84]=pass, (84..100]=excellent, (100.. + ∞)=invalid} RangeMap merges connected ranges: {(-∞..0)=invalid, [0..60)=fail, [60..100]=pass, (100.. + ∞)=invalid} RangeMap minimum range: (-∞.. + ∞) RangeMap sub-range Map: {[70..84]=pass, (84..90]=excellent} RangeMap merge Map: [(-∞..0)=invalid, [0..60)=fail, [60..84]=pass, (84..100]=pass, (100.. + ∞) =invalid] RangeMap removes the range: [(-∞..0)=invalid, [0..60)=fail, [60..84]=pass, (84..90]=pass, [95..100] =pass, (100.. + ∞)=invalid] RangeMap clears all ranges: []
7. ClassToInstanceMap – Type mapping to instance Map
Official Note Translation: A mapping whose each entry maps a Java primitive type to an instance of that type. In addition to implementing Map, additional type-safe operations putInstance and getInstance are provided. Like any other Map
Sample code (Requirement: cache beans (not handed over to Spring for management, manage beans yourself)):
class UserBean { private final Integer id; private final String username; public UserBean(Integer id, String username) { this.id = id; this.username = username; } @Override public String toString() { return "UserBean{" + "id=" + id + ", username='" + username + '\'' + '}'; } } //Create Bean UserBean userBean = new UserBean(1, "Zhang San"); // HashMap HashMap<Class, Object> hashMap = new HashMap<>(); hashMap.put(UserBean.class, userBean); // Get value, need to force transfer UserBean value = (UserBean) hashMap.get(UserBean.class); System.out.println("HashMap gets object instance: " + value); System.out.println("HashMap gets the object instance equal to the created Bean: " + (value == userBean)); // Create ClassToInstanceMap ClassToInstanceMap<Object> classToInstanceMap = MutableClassToInstanceMap.create(); classToInstanceMap.putInstance(UserBean.class, userBean); // Get the value, no need to force transfer UserBean value2 = classToInstanceMap.getInstance(UserBean.class); System.out.println("\\ ClassToInstanceMap Get object instance: " + value2); System.out.println("ClassToInstanceMap gets the object instance equal to the created Bean: " + (value2 == userBean)); //Create an immutable ClassToInstanceMap, which cannot be added, updated or deleted ClassToInstanceMap<UserBean> immutableClassToInstanceMap = ImmutableClassToInstanceMap.<UserBean>builder() .put(UserBean.class, userBean) .build(); // Get the value, no need to force transfer UserBean value3 = immutableClassToInstanceMap.getInstance(UserBean.class); System.out.println("\\ ImmutableClassToInstanceMap Get object instance: " + value3); System.out.println("ImmutableClassToInstanceMap gets the object instance equal to the created Bean: " + (value3 == userBean)); // Restrict the type to avoid using HashMap to store objects. Because the Object value type is used, type verification is required when adding cache. ClassToInstanceMap<Collection> classToInstanceMap1 = MutableClassToInstanceMap.create(); classToInstanceMap1.put(ArrayList.class, new ArrayList()); classToInstanceMap1.put(HashSet.class, new HashSet()); // Compile and save: 'put(java.lang.Class<? extends [email protected] Collection>, java.util.Collection)' in 'com.google .common.collect.MutableClassToInstanceMap' cannot be applied to '(java.lang.Class<java.util.HashMap>, java.util.HashMap)' // classToInstanceMap1.put(HashMap.class, new HashMap());
Results of the:
HashMap gets object instance: UserBean{id=1, username='Zhang San'} HashMap gets the object instance equal to the created Bean: true ClassToInstanceMap gets the object instance: UserBean{id=1, username='Zhang San'} ClassToInstanceMap gets the object instance equal to the created Bean: true ImmutableClassToInstanceMap gets the object instance: UserBean{id=1, username='Zhang San'} ImmutableClassToInstanceMap gets the object instance equal to the created Bean: true