Guava Library for Collections in Java

Introduction to Guava Collections

Google Guava is a powerful open-source Java library that provides utility methods for collections, caching, primitives support, concurrency, common annotations, string processing, I/O, and more. The collections module is particularly rich, offering immutable collections, new collection types, and utility classes that greatly enhance Java's standard collections framework.

Maven Dependency

<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>32.1.3-jre</version> </dependency>

Immutable Collections

Creating Immutable Collections

import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; import java.util.*; public class ImmutableCollectionsExample { public static void main(String[] args) { // 1. Using of() method for small collections ImmutableList<String> immutableList = ImmutableList.of("a", "b", "c"); ImmutableSet<Integer> immutableSet = ImmutableSet.of(1, 2, 3, 4, 5); ImmutableMap<String, Integer> immutableMap = ImmutableMap.of( "one", 1, "two", 2, "three", 3 ); System.out.println("Immutable List: " + immutableList); System.out.println("Immutable Set: " + immutableSet); System.out.println("Immutable Map: " + immutableMap); // 2. Using copyOf() from existing collections List<String> mutableList = new ArrayList<>(); mutableList.add("apple"); mutableList.add("banana"); mutableList.add("cherry"); ImmutableList<String> copiedList = ImmutableList.copyOf(mutableList); System.out.println("Copied Immutable List: " + copiedList); // 3. Using Builder for complex constructions ImmutableList<String> builtList = ImmutableList.<String>builder() .add("red") .addAll(mutableList) .add("blue", "green") .build(); System.out.println("Built Immutable List: " + builtList); // 4. Immutable Map with Builder ImmutableMap<String, String> builtMap = ImmutableMap.<String, String>builder() .put("key1", "value1") .put("key2", "value2") .put("key3", "value3") .build(); System.out.println("Built Immutable Map: " + builtMap); // 5. Attempting to modify immutable collections (will throw exception) try { immutableList.add("new element"); // Throws UnsupportedOperationException } catch (UnsupportedOperationException e) { System.out.println("Cannot modify immutable list: " + e.getMessage()); } // 6. Immutable collections from arrays String[] array = {"x", "y", "z"}; ImmutableList<String> fromArray = ImmutableList.copyOf(array); System.out.println("From array: " + fromArray); } }

Advantages of Immutable Collections

import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.List; public class ImmutableAdvantages { // Thread-safe without synchronization public static class SharedData { private final ImmutableList<String> data; public SharedData(List<String> input) { this.data = ImmutableList.copyOf(input); } public List<String> getData() { return data; // Safe to share without defensive copying } } // Constants public static final ImmutableList<String> DAYS_OF_WEEK = ImmutableList.of( "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" ); // Defensive copying in APIs public static class DataProcessor { private final ImmutableList<String> processedData; public DataProcessor(List<String> rawData) { // Defensive copy that's efficient and safe this.processedData = ImmutableList.copyOf(rawData); } public List<String> getProcessedData() { return processedData; // No need for defensive copy } } public static void main(String[] args) { // Memory efficiency - no synchronization needed SharedData shared = new SharedData(List.of("a", "b", "c")); // Multiple threads can safely access the data Runnable task = () -> { System.out.println(Thread.currentThread().getName() + ": " + shared.getData()); }; Thread t1 = new Thread(task); Thread t2 = new Thread(task); t1.start(); t2.start(); // Constants usage System.out.println("Days: " + DAYS_OF_WEEK); } }

New Collection Types

Multiset (Bag)

import com.google.common.collect.*; import java.util.*; public class MultisetExample { public static void main(String[] args) { // 1. Creating and using Multiset Multiset<String> multiset = HashMultiset.create(); // Add elements with counts multiset.add("apple"); multiset.add("banana"); multiset.add("apple"); multiset.add("cherry"); multiset.add("banana"); multiset.add("apple"); System.out.println("Multiset: " + multiset); System.out.println("Count of apple: " + multiset.count("apple")); System.out.println("Count of banana: " + multiset.count("banana")); System.out.println("Unique elements: " + multiset.elementSet()); // 2. Set specific counts multiset.setCount("apple", 5); System.out.println("After setting apple count to 5: " + multiset); // 3. Remove elements multiset.remove("apple", 2); System.out.println("After removing 2 apples: " + multiset); // 4. Different Multiset implementations Multiset<String> treeMultiset = TreeMultiset.create(); treeMultiset.add("zebra"); treeMultiset.add("apple"); treeMultiset.add("banana"); treeMultiset.add("apple"); System.out.println("TreeMultiset (sorted): " + treeMultiset); // 5. LinkedHashMultiset preserves insertion order Multiset<String> linkedMultiset = LinkedHashMultiset.create(); linkedMultiset.add("zebra"); linkedMultiset.add("apple"); linkedMultiset.add("banana"); System.out.println("LinkedHashMultiset: " + linkedMultiset); // 6. Practical example - word frequency counter String text = "the quick brown fox jumps over the lazy dog the fox is quick"; Multiset<String> wordFrequency = HashMultiset.create(); for (String word : text.split(" ")) { wordFrequency.add(word.toLowerCase()); } System.out.println("\nWord frequencies:"); for (String word : wordFrequency.elementSet()) { System.out.println(word + ": " + wordFrequency.count(word)); } // 7. Converting to traditional collections Set<String> uniqueWords = wordFrequency.elementSet(); System.out.println("Unique words: " + uniqueWords); } }

Multimap (One-to-Many Mapping)

import com.google.common.collect.*; import java.util.*; public class MultimapExample { public static void main(String[] args) { // 1. ArrayListMultimap - values stored in ArrayList ArrayListMultimap<String, String> arrayListMultimap = ArrayListMultimap.create(); arrayListMultimap.put("fruits", "apple"); arrayListMultimap.put("fruits", "banana"); arrayListMultimap.put("fruits", "cherry"); arrayListMultimap.put("vegetables", "carrot"); arrayListMultimap.put("vegetables", "broccoli"); arrayListMultimap.put("fruits", "apple"); // Duplicates allowed System.out.println("ArrayListMultimap: " + arrayListMultimap); System.out.println("Fruits: " + arrayListMultimap.get("fruits")); System.out.println("Vegetables: " + arrayListMultimap.get("vegetables")); // 2. HashMultimap - values stored in HashSet (no duplicates) HashMultimap<String, String> hashMultimap = HashMultimap.create(); hashMultimap.put("colors", "red"); hashMultimap.put("colors", "blue"); hashMultimap.put("colors", "green"); hashMultimap.put("colors", "red"); // Duplicate ignored System.out.println("\nHashMultimap: " + hashMultimap); System.out.println("Colors: " + hashMultimap.get("colors")); // 3. LinkedHashMultimap - preserves insertion order LinkedHashMultimap<String, String> linkedMultimap = LinkedHashMultimap.create(); linkedMultimap.put("letters", "z"); linkedMultimap.put("letters", "a"); linkedMultimap.put("letters", "c"); System.out.println("\nLinkedHashMultimap: " + linkedMultimap); System.out.println("Letters: " + linkedMultimap.get("letters")); // 4. TreeMultimap - sorted keys and values TreeMultimap<String, Integer> treeMultimap = TreeMultimap.create(); treeMultimap.put("scores", 85); treeMultimap.put("scores", 92); treeMultimap.put("scores", 78); treeMultimap.put("ages", 25); treeMultimap.put("ages", 30); System.out.println("\nTreeMultimap: " + treeMultimap); // 5. Practical example - student courses Multimap<String, String> studentCourses = ArrayListMultimap.create(); studentCourses.put("Alice", "Math"); studentCourses.put("Alice", "Physics"); studentCourses.put("Bob", "Chemistry"); studentCourses.put("Bob", "Biology"); studentCourses.put("Bob", "Math"); studentCourses.put("Charlie", "Physics"); System.out.println("\nStudent Courses:"); for (String student : studentCourses.keySet()) { System.out.println(student + ": " + studentCourses.get(student)); } // 6. Views and transformations Map<String, Collection<String>> asMap = studentCourses.asMap(); System.out.println("\nAs Map: " + asMap); // 7. Remove and replace operations studentCourses.remove("Alice", "Physics"); System.out.println("After removing Physics from Alice: " + studentCourses.get("Alice")); studentCourses.replaceValues("Bob", Arrays.asList("Art", "Music")); System.out.println("After replacing Bob's courses: " + studentCourses.get("Bob")); } }

BiMap (Two-Way Map)

import com.google.common.collect.*; import java.util.*; public class BiMapExample { public static void main(String[] args) { // 1. HashBiMap - two-way mapping HashBiMap<String, Integer> biMap = HashBiMap.create(); biMap.put("one", 1); biMap.put("two", 2); biMap.put("three", 3); System.out.println("BiMap: " + biMap); System.out.println("Key for value 2: " + biMap.inverse().get(2)); System.out.println("Value for key 'three': " + biMap.get("three")); // 2. Inverse view BiMap<Integer, String> inverseBiMap = biMap.inverse(); System.out.println("Inverse BiMap: " + inverseBiMap); // 3. Force put - will throw if value already exists try { biMap.put("uno", 1); // Throws IllegalArgumentException } catch (IllegalArgumentException e) { System.out.println("Cannot put duplicate value: " + e.getMessage()); } // 4. Force put with overwrite biMap.forcePut("uno", 1); // Removes "one" -> 1 mapping System.out.println("After forcePut: " + biMap); // 5. EnumBiMap - for enum keys and values enum Color { RED, GREEN, BLUE } enum Code { R, G, B } EnumBiMap<Color, Code> enumBiMap = EnumBiMap.create(Color.class, Code.class); enumBiMap.put(Color.RED, Code.R); enumBiMap.put(Color.GREEN, Code.G); enumBiMap.put(Color.BLUE, Code.B); System.out.println("EnumBiMap: " + enumBiMap); System.out.println("Inverse: " + enumBiMap.inverse()); // 6. Practical example - country codes HashBiMap<String, String> countryCodes = HashBiMap.create(); countryCodes.put("United States", "US"); countryCodes.put("United Kingdom", "UK"); countryCodes.put("Canada", "CA"); countryCodes.put("Australia", "AU"); System.out.println("\nCountry Codes:"); System.out.println("Code for Canada: " + countryCodes.get("Canada")); System.out.println("Country for AU: " + countryCodes.inverse().get("AU")); // 7. ImmutableBiMap ImmutableBiMap<String, Integer> immutableBiMap = ImmutableBiMap.of( "first", 1, "second", 2, "third", 3 ); System.out.println("\nImmutableBiMap: " + immutableBiMap); System.out.println("Inverse: " + immutableBiMap.inverse()); } }

Table (Two-Dimensional Map)

import com.google.common.collect.*; import java.util.*; public class TableExample { public static void main(String[] args) { // 1. HashBasedTable - most commonly used Table<String, String, Double> distanceTable = HashBasedTable.create(); distanceTable.put("New York", "Boston", 215.0); distanceTable.put("New York", "Washington DC", 225.0); distanceTable.put("Boston", "Washington DC", 440.0); distanceTable.put("Chicago", "Detroit", 283.0); System.out.println("Distance Table: " + distanceTable); System.out.println("NY to Boston: " + distanceTable.get("New York", "Boston")); // 2. Row and column views Map<String, Double> nyDistances = distanceTable.row("New York"); System.out.println("Distances from NY: " + nyDistances); Map<String, Double> bostonDistances = distanceTable.column("Boston"); System.out.println("Distances to Boston: " + bostonDistances); // 3. TreeBasedTable - sorted rows and columns TreeBasedTable<String, String, Integer> sortedTable = TreeBasedTable.create(); sortedTable.put("zebra", "apple", 1); sortedTable.put("apple", "zebra", 2); sortedTable.put("banana", "cherry", 3); System.out.println("\nTreeBasedTable (sorted): " + sortedTable); // 4. ArrayTable - fixed rows and columns List<String> rows = Arrays.asList("row1", "row2", "row3"); List<String> columns = Arrays.asList("col1", "col2", "col3"); ArrayTable<String, String, String> arrayTable = ArrayTable.create(rows, columns); arrayTable.put("row1", "col1", "value11"); arrayTable.put("row1", "col2", "value12"); arrayTable.put("row2", "col1", "value21"); System.out.println("\nArrayTable: " + arrayTable); // 5. Practical example - student grades Table<String, String, Integer> gradeTable = HashBasedTable.create(); gradeTable.put("Alice", "Math", 85); gradeTable.put("Alice", "Science", 92); gradeTable.put("Bob", "Math", 78); gradeTable.put("Bob", "Science", 88); gradeTable.put("Charlie", "Math", 95); gradeTable.put("Charlie", "Science", 90); System.out.println("\nGrade Table:"); System.out.println("Alice's Math grade: " + gradeTable.get("Alice", "Math")); // 6. Row and column operations Set<String> students = gradeTable.rowKeySet(); Set<String> subjects = gradeTable.columnKeySet(); System.out.println("Students: " + students); System.out.println("Subjects: " + subjects); // 7. Cell iteration System.out.println("\nAll grades:"); for (Table.Cell<String, String, Integer> cell : gradeTable.cellSet()) { System.out.printf("%s - %s: %d%n", cell.getRowKey(), cell.getColumnKey(), cell.getValue()); } // 8. Transforming tables Table<String, String, String> formattedTable = Tables.transformValues( gradeTable, grade -> grade >= 90 ? "A" : grade >= 80 ? "B" : "C" ); System.out.println("\nFormatted Grades: " + formattedTable); } }

Collection Utilities

Lists Utilities

import com.google.common.collect.*; import java.util.*; public class ListsUtilitiesExample { public static void main(String[] args) { // 1. Creating lists with factory methods List<String> list1 = Lists.newArrayList("a", "b", "c"); List<Integer> list2 = Lists.newArrayList(1, 2, 3, 4, 5); List<String> list3 = Lists.newArrayListWithCapacity(100); System.out.println("List1: " + list1); System.out.println("List2: " + list2); // 2. Transformations and partitions List<List<Integer>> partitions = Lists.partition(list2, 2); System.out.println("Partitions of size 2: " + partitions); // 3. Reverse view List<String> reversed = Lists.reverse(list1); System.out.println("Reversed: " + reversed); // 4. Character lists from strings List<Character> chars = Lists.charactersOf("hello"); System.out.println("Characters: " + chars); // 5. Cartesian product List<List<String>> cartesian = Lists.cartesianProduct( Arrays.asList("a", "b"), Arrays.asList("1", "2") ); System.out.println("Cartesian product: " + cartesian); // 6. Transform with function List<String> transformed = Lists.transform(list2, i -> "number-" + i); System.out.println("Transformed: " + transformed); // Practical examples List<String> names = Lists.newArrayList("Alice", "Bob", "Charlie", "David"); // Batch processing int batchSize = 2; List<List<String>> batches = Lists.partition(names, batchSize); System.out.println("\nBatch processing:"); for (int i = 0; i < batches.size(); i++) { System.out.println("Batch " + (i + 1) + ": " + batches.get(i)); } // Reverse for LIFO behavior List<String> stackLike = Lists.newArrayList(); stackLike.add("first"); stackLike.add("second"); stackLike.add("third"); List<String> lifoView = Lists.reverse(stackLike); System.out.println("\nLIFO view: " + lifoView); System.out.println("First to process: " + lifoView.get(0)); } }

Sets Utilities

import com.google.common.collect.*; import java.util.*; public class SetsUtilitiesExample { public static void main(String[] args) { Set<String> set1 = Sets.newHashSet("a", "b", "c", "d"); Set<String> set2 = Sets.newHashSet("c", "d", "e", "f"); System.out.println("Set1: " + set1); System.out.println("Set2: " + set2); // 1. Union Set<String> union = Sets.union(set1, set2); System.out.println("Union: " + union); // 2. Intersection Set<String> intersection = Sets.intersection(set1, set2); System.out.println("Intersection: " + intersection); // 3. Difference Set<String> difference = Sets.difference(set1, set2); System.out.println("Difference (set1 - set2): " + difference); // 4. Symmetric difference Set<String> symmetricDifference = Sets.symmetricDifference(set1, set2); System.out.println("Symmetric difference: " + symmetricDifference); // 5. Power set Set<String> smallSet = Sets.newHashSet("a", "b", "c"); Set<Set<String>> powerSet = Sets.powerSet(smallSet); System.out.println("\nPower set of " + smallSet + ":"); for (Set<String> subset : powerSet) { System.out.println(" " + subset); } // 6. Cartesian product Set<List<String>> cartesian = Sets.cartesianProduct( Sets.newHashSet("x", "y"), Sets.newHashSet("1", "2") ); System.out.println("\nCartesian product: " + cartesian); // 7. Filtering sets Set<String> filtered = Sets.filter(set1, s -> s.compareTo("c") >= 0); System.out.println("Filtered (>= 'c'): " + filtered); // 8. Combinations Set<Set<String>> combinations = Sets.combinations(smallSet, 2); System.out.println("\nCombinations of size 2: " + combinations); // Practical example - tag system Set<String> user1Tags = Sets.newHashSet("java", "programming", "coding"); Set<String> user2Tags = Sets.newHashSet("programming", "development", "coding"); Set<String> commonTags = Sets.intersection(user1Tags, user2Tags); Set<String> allTags = Sets.union(user1Tags, user2Tags); Set<String> uniqueToUser1 = Sets.difference(user1Tags, user2Tags); System.out.println("\nTag Analysis:"); System.out.println("Common tags: " + commonTags); System.out.println("All tags: " + allTags); System.out.println("Unique to user1: " + uniqueToUser1); } }

Maps Utilities

import com.google.common.collect.*; import java.util.*; import java.util.function.Function; public class MapsUtilitiesExample { public static void main(String[] args) { // 1. Creating maps Map<String, Integer> map1 = Maps.newHashMap(); Map<String, String> map2 = Maps.newLinkedHashMap(); // 2. Unique index List<Person> people = Arrays.asList( new Person(1, "Alice"), new Person(2, "Bob"), new Person(3, "Charlie") ); Map<Integer, Person> idToPerson = Maps.uniqueIndex(people, Person::getId); System.out.println("ID to Person map: " + idToPerson); // 3. Transform values Map<Integer, String> idToName = Maps.transformValues(idToPerson, Person::getName); System.out.println("ID to Name map: " + idToName); // 4. Difference between maps Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3); Map<String, Integer> right = ImmutableMap.of("a", 1, "b", 4, "d", 5); MapDifference<String, Integer> difference = Maps.difference(left, right); System.out.println("\nMap Difference:"); System.out.println("Entries in common: " + difference.entriesInCommon()); System.out.println("Entries differing: " + difference.entriesDiffering()); System.out.println("Entries only in left: " + difference.entriesOnlyOnLeft()); System.out.println("Entries only in right: " + difference.entriesOnlyOnRight()); // 5. Filtering maps Map<String, Integer> filtered = Maps.filterValues(left, value -> value > 1); System.out.println("Filtered (values > 1): " + filtered); // 6. AsMap from set Set<String> keys = Sets.newHashSet("key1", "key2", "key3"); Map<String, String> generatedMap = Maps.asMap(keys, key -> "value-for-" + key); System.out.println("Generated map: " + generatedMap); // Practical example - configuration processing Map<String, String> defaultConfig = ImmutableMap.of( "host", "localhost", "port", "8080", "timeout", "30" ); Map<String, String> userConfig = ImmutableMap.of( "host", "example.com", "port", "9090", "database", "mydb" ); MapDifference<String, String> configDiff = Maps.difference(defaultConfig, userConfig); System.out.println("\nConfiguration Analysis:"); System.out.println("Common settings: " + configDiff.entriesInCommon()); System.out.println("Changed settings: " + configDiff.entriesDiffering()); System.out.println("Default only: " + configDiff.entriesOnlyOnLeft()); System.out.println("User only: " + configDiff.entriesOnlyOnRight()); // Merge strategy Map<String, String> merged = new HashMap<>(defaultConfig); merged.putAll(userConfig); // User config overrides defaults System.out.println("Merged config: " + merged); } static class Person { private final int id; private final String name; public Person(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public String getName() { return name; } @Override public String toString() { return name + "(" + id + ")"; } } }

Advanced Collection Features

Range and RangeSet

import com.google.common.collect.*; import java.util.*; public class RangeExample { public static void main(String[] args) { // 1. Creating ranges Range<Integer> closedRange = Range.closed(1, 10); // [1, 10] Range<Integer> openRange = Range.open(1, 10); // (1, 10) Range<Integer> closedOpen = Range.closedOpen(1, 10); // [1, 10) Range<Integer> openClosed = Range.openClosed(1, 10); // (1, 10] System.out.println("Closed [1,10]: " + closedRange); System.out.println("Open (1,10): " + openRange); System.out.println("Contains 5 in closed: " + closedRange.contains(5)); System.out.println("Contains 1 in open: " + openRange.contains(1)); // 2. Range operations Range<Integer> range1 = Range.closed(1, 5); Range<Integer> range2 = Range.closed(3, 8); System.out.println("\nRange Operations:"); System.out.println("Range1: " + range1); System.out.println("Range2: " + range2); System.out.println("Union: " + range1.span(range2)); System.out.println("Intersection: " + range1.intersection(range2)); System.out.println("Is connected: " + range1.isConnected(range2)); // 3. RangeSet RangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(1, 10)); rangeSet.add(Range.closed(15, 20)); rangeSet.add(Range.closed(5, 12)); // Merges with first range System.out.println("\nRangeSet: " + rangeSet); System.out.println("Contains 8: " + rangeSet.contains(8)); System.out.println("Contains 13: " + rangeSet.contains(13)); System.out.println("Range containing 8: " + rangeSet.rangeContaining(8)); // 4. Practical example - age groups RangeSet<Integer> ageGroups = TreeRangeSet.create(); ageGroups.add(Range.closedOpen(0, 13)); // Child ageGroups.add(Range.closedOpen(13, 20)); // Teen ageGroups.add(Range.closedOpen(20, 65)); // Adult ageGroups.add(Range.atLeast(65)); // Senior System.out.println("\nAge Groups:"); int[] testAges = {5, 15, 25, 70}; for (int age : testAges) { System.out.println("Age " + age + ": " + (ageGroups.contains(age) ? "Valid" : "Invalid")); } // 5. Complement RangeSet<Integer> complement = rangeSet.complement(); System.out.println("\nComplement of rangeSet: " + complement); } }

Ordering and Comparison

import com.google.common.collect.*; import java.util.*; import java.util.Comparator; public class OrderingExample { public static void main(String[] args) { List<String> names = Arrays.asList("Charlie", "Alice", "Bob", "David"); // 1. Natural ordering Ordering<String> natural = Ordering.natural(); List<String> sortedNatural = natural.sortedCopy(names); System.out.println("Natural order: " + sortedNatural); // 2. Reverse ordering Ordering<String> reverse = natural.reverse(); List<String> sortedReverse = reverse.sortedCopy(names); System.out.println("Reverse order: " + sortedReverse); // 3. Custom ordering Ordering<String> byLength = new Ordering<String>() { @Override public int compare(String left, String right) { return Integer.compare(left.length(), right.length()); } }; List<String> sortedByLength = byLength.sortedCopy(names); System.out.println("By length: " + sortedByLength); // 4. Compound ordering Ordering<String> byLengthThenNatural = byLength.compound(natural); List<String> compoundSorted = byLengthThenNatural.sortedCopy(names); System.out.println("By length then natural: " + compoundSorted); // 5. Null handling List<String> namesWithNull = Arrays.asList("Charlie", null, "Alice", "Bob", null); Ordering<String> nullsFirst = natural.nullsFirst(); Ordering<String> nullsLast = natural.nullsLast(); System.out.println("Nulls first: " + nullsFirst.sortedCopy(namesWithNull)); System.out.println("Nulls last: " + nullsLast.sortedCopy(namesWithNull)); // 6. Min and max String shortest = byLength.min(names); String longest = byLength.max(names); System.out.println("Shortest: " + shortest); System.out.println("Longest: " + longest); // 7. Greatest/Lessest of List<String> top3Longest = byLength.greatestOf(names, 3); List<String> bottom2Shortest = byLength.leastOf(names, 2); System.out.println("Top 3 longest: " + top3Longest); System.out.println("Bottom 2 shortest: " + bottom2Shortest); // Practical example - student sorting List<Student> students = Arrays.asList( new Student("Alice", 85, 20), new Student("Bob", 92, 22), new Student("Charlie", 78, 19), new Student("David", 92, 21) ); // Sort by grade descending, then by age ascending Ordering<Student> byGrade = Ordering.natural().reverse().onResultOf(Student::getGrade); Ordering<Student> byAge = Ordering.natural().onResultOf(Student::getAge); Ordering<Student> compound = byGrade.compound(byAge); List<Student> sortedStudents = compound.sortedCopy(students); System.out.println("\nStudents sorted by grade then age:"); sortedStudents.forEach(s -> System.out.println(s)); } static class Student { private final String name; private final int grade; private final int age; public Student(String name, int grade, int age) { this.name = name; this.grade = grade; this.age = age; } public String getName() { return name; } public int getGrade() { return grade; } public int getAge() { return age; } @Override public String toString() { return String.format("%s (Grade: %d, Age: %d)", name, grade, age); } } }

Best Practices and Performance

import com.google.common.collect.*; import java.util.*; public class BestPractices { // 1. Prefer immutable collections for constants and shared data public static final ImmutableList<String> CONSTANT_LIST = ImmutableList.of("value1", "value2", "value3"); // 2. Use appropriate collection types public static class CollectionChoices { // Use Multiset for counting public Multiset<String> countWords(String text) { Multiset<String> wordCount = HashMultiset.create(); for (String word : text.split("\\s+")) { wordCount.add(word.toLowerCase()); } return wordCount; } // Use Multimap for one-to-many relationships public Multimap<String, String> groupByCategory(List<Item> items) { Multimap<String, String> categorized = ArrayListMultimap.create(); for (Item item : items) { categorized.put(item.getCategory(), item.getName()); } return categorized; } // Use BiMap for two-way lookup public BiMap<String, Integer> createLookupTable(List<String> items) { BiMap<String, Integer> lookup = HashBiMap.create(); for (int i = 0; i < items.size(); i++) { lookup.put(items.get(i), i); } return lookup; } } // 3. Efficient collection creation public static class EfficientCollections { // Know the expected size in advance public List<String> createSizedList(int expectedSize) { return Lists.newArrayListWithExpectedSize(expectedSize); } // Use builders for complex immutable collections public ImmutableMap<String, String> buildComplexMap() { return ImmutableMap.<String, String>builder() .put("key1", "value1") .put("key2", "value2") .put("key3", "value3") .build(); } } // 4. Avoid common pitfalls public static class Pitfalls { // Don't modify collections during iteration public void safeModification(List<String> list) { // Instead of modifying during iteration, use: List<String> toRemove = new ArrayList<>(); for (String item : list) { if (shouldRemove(item)) { toRemove.add(item); } } list.removeAll(toRemove); } // Be careful with lazy transformations public void carefulWithTransform(List<Integer> numbers) { List<String> strings = Lists.transform(numbers, String::valueOf); // The transformation is applied on each access // Consider copying if you need to access multiple times List<String> copiedStrings = ImmutableList.copyOf(strings); } private boolean shouldRemove(String item) { return item.startsWith("remove"); } } static class Item { private final String category; private final String name; public Item(String category, String name) { this.category = category; this.name = name; } public String getCategory() { return category; } public String getName() { return name; } } public static void main(String[] args) { BestPractices practices = new BestPractices(); // Demonstrate best practices String text = "hello world hello java world programming"; Multiset<String> wordCount = new CollectionChoices().countWords(text); System.out.println("Word counts: " + wordCount); // Show efficient collection usage List<String> sizedList = new EfficientCollections().createSizedList(1000); System.out.println("Created list with expected size 1000"); // Constants usage System.out.println("Constant list: " + CONSTANT_LIST); } }

Guava's collection utilities provide powerful, efficient, and well-tested alternatives to Java's standard collections. They help write cleaner, more maintainable code while providing additional functionality not available in the JDK.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper