Guava库提供了丰富的集合类API,这些API扩展了Java标准库中的集合功能,提供了更多的灵活性和便利性。
在日常开发中,集合类是我们日常编程不可或缺的一部分。Java标准库为我们提供了一套基本的集合类,但在实际项目中,我们往往需要更加灵活和强大的集合功能。这时,Google的Guava库便成为了我们的得力助手。Guava库扩展了Java的集合类,提供了一系列高效、实用且易于使用的集合API。在本文中,我们将深入探索Guava库中常用的集合类API,并了解它们如何提升我们的开发效率。
不可变集合:守护数据的永恒之石
首先,我们要介绍的是Guava提供的不可变集合。在编程中,有时我们需要创建一些一旦初始化就不会再更改的集合。这些集合被称为不可变集合。Guava为我们提供了ImmutableList、ImmutableSet和ImmutableMap等不可变集合的实现。这些集合在创建时确定了内容,并且保证了之后无法修改。这种不可变性带来了诸多好处,比如线程安全、减少错误和提高代码可读性。当你需要一个不会变动的集合时,Guava的不可变集合将是你的最佳选择。
其他API敬请期待后续文章
1. ImmutableList
一个不可变的列表实现,提供了与Java List接口类似的方法,但保证了列表内容不可更改。
2. ImmutableSet
一个不可变的集合实现,与Java Set接口类似,但不允许添加或删除元素。
3. ImmutableMap
一个不可变的映射实现,类似于Java的Map接口,但键值对是固定的,无法修改。
这些不可变集合在创建时确定内容,之后不可更改,有助于编写线程安全的代码。
在pom.xml中添加如下依赖:
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.0.1-jre</version> <!-- 请检查是否有更新的版本 --> </dependency>
然后,在你的Java代码中使用这些不可变集合:
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableMap; public class GuavaImmutableCollectionsExample { public static void main(String[] args) { // 创建一个ImmutableList ImmutableList<String> immutableList = ImmutableList.of("Apple", "Banana", "Cherry"); System.out.println("ImmutableList: " + immutableList); // 尝试修改ImmutableList(这将导致编译时错误) // immutableList.add("Date"); // 这行代码将无法编译 // 创建一个ImmutableSet ImmutableSet<Integer> immutableSet = ImmutableSet.of(1, 2, 3, 4, 5); System.out.println("ImmutableSet: " + immutableSet); // 尝试修改ImmutableSet(这也将导致编译时错误) // immutableSet.add(6); // 这行代码也无法编译 // 创建一个ImmutableMap ImmutableMap<String, Integer> immutableMap = ImmutableMap.of("One", 1, "Two", 2, "Three", 3); System.out.println("ImmutableMap: " + immutableMap); // 尝试修改ImmutableMap(这同样会导致编译时错误) // immutableMap.put("Four", 4); // 这行代码也无法编译 // 访问ImmutableMap中的元素 Integer value = immutableMap.get("Two"); System.out.println("Value associated with 'Two': " + value); } }
在上面的代码中,我们展示了如何使用Guava的不可变集合类来创建列表、集合和映射,并尝试(不成功地)修改它们。由于这些集合是不可变的,任何尝试修改它们的操作都会在编译时失败。这对于需要确保数据一致性和线程安全的场景非常有用。
ImmutableTable、ImmutableEnumSet 和 ImmutableEnumMap 在Guava并没有直接提供这些具体的实现。在实际使用中,你应该根据具体的需求选择合适的不可变集合类型,并结合 Java 标准库和 Guava
提供的工具来创建和操作这些集合
4. ImmutableSortedSet 和 ImmutableSortedMap
这两个接口分别表示不可变的排序集合和排序映射。它们提供了根据元素的自然顺序或指定的比较器排序的功能。例如:
import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.Ordering; import java.util.Comparator; public class GuavaImmutableSortedCollectionsExample { public static void main(String[] args) { // 创建一个根据自然顺序排序的ImmutableSortedSet ImmutableSortedSet<Integer> sortedSet = ImmutableSortedSet.copyOf(Ordering.natural(), 10, 5, 15, 20); System.out.println("ImmutableSortedSet (natural order): " + sortedSet); // 创建一个根据自定义比较器排序的ImmutableSortedSet Comparator<String> stringComparator = Comparator.comparing(String::length); ImmutableSortedSet<String> sortedSetCustomOrder = ImmutableSortedSet.copyOf(stringComparator, "apple", "banana", "kiwi", "pear"); System.out.println("ImmutableSortedSet (custom order): " + sortedSetCustomOrder); // 创建一个根据自然顺序排序键的ImmutableSortedMap ImmutableSortedMap<Integer, String> sortedMap = ImmutableSortedMap.of(5, "five", 1, "one", 3, "three"); // 注意:上面的of方法会根据键的自然顺序对条目进行排序,但这里我们传入的已经是排序好的键值对 System.out.println("ImmutableSortedMap (natural order): " + sortedMap); // 创建一个根据自定义比较器排序键的ImmutableSortedMap ImmutableSortedMap<String, Integer> sortedMapCustomOrder = ImmutableSortedMap.orderedBy(stringComparator) .put("apple", 1) .put("banana", 2) .put("kiwi", 3) .put("pear", 4) .build(); System.out.println("ImmutableSortedMap (custom order): " + sortedMapCustomOrder); } }
5. ImmutableMultiset 和 ImmutableMultimap
这两个接口分别表示不可变的多重集和多重映射。多重集允许元素重复出现,而多重映射则允许一个键映射到多个值。例如:
import com.google.common.collect.ImmutableMultiset; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Multiset; import com.google.common.collect.Multimap; import java.util.Arrays; public class GuavaImmutableMultiCollectionsExample { public static void main(String[] args) { // 创建一个ImmutableMultiset ImmutableMultiset<String> multiset = ImmutableMultiset.<String>builder() .addAll(Arrays.asList("apple", "apple", "banana", "orange")) .addCopies("banana", 2) // 添加额外的"banana"元素 .build(); System.out.println("ImmutableMultiset: " + multiset); // 展示元素及其出现次数 for (Multiset.Entry<String> entry : multiset.entrySet()) { System.out.println(entry.getElement() + ": " + entry.getCount()); } // 创建一个ImmutableMultimap ImmutableMultimap<String, Integer> multimap = ImmutableMultimap.<String, Integer>builder() .putAll("fruits", Arrays.asList(1, 2, 3)) .putAll("veggies", Arrays.asList(4, 5)) .put("fruits", 6) // 添加额外的键值对到"fruits" .build(); System.out.println("ImmutableMultimap: " + multimap); // 展示键及其对应的值 for (String key : multimap.keySet()) { System.out.println(key + " => " + multimap.get(key)); } } }
在这个示例中,我们展示了如何创建 ImmutableMultiset 和 ImmutableMultimap。ImmutableMultiset 允许元素重复出现,并且我们可以使用 addCopies 方法来添加指定数量的元素。ImmutableMultimap 允许一个键映射到多个值。
输出将类似于以下内容:
ImmutableMultiset: [apple x 2, banana x 3, orange] apple: 2 banana: 3 orange: 1 ImmutableMultimap: {fruits=[1, 2, 3, 6], veggies=[4, 5]} fruits => [1, 2, 3, 6] veggies => [4, 5]
请注意,ImmutableMultiset 和 ImmutableMultimap 都是不可变的,这意味着一旦创建,您就不能向它们添加或删除元素。如果您需要一个可变的版本,可以使用 Multiset 和 Multimap 接口的其他实现,例如 HashMultiset 和 ArrayListMultimap,然后在需要的时候使用 ImmutableMultiset.copyOf(multiset) 或 ImmutableMultimap.copyOf(multimap) 来创建不可变副本。
6. ImmutableTable
ImmutableTable 是 Google Guava 库中提供的一种不可变的三维表格数据结构。它类似于 ImmutableMap,但是它可以存储两个键和一个值的映射关系,可以看作是一种特殊的集合。它允许你通过行和列来访问元素。例如:
import com.google.common.collect.ImmutableTable; import com.google.common.collect.Table; import java.util.Map; public class GuavaImmutableTableExample { public static void main(String[] args) { // 创建一个ImmutableTable ImmutableTable<String, String, Integer> table = ImmutableTable.<String, String, Integer>builder() .put("apple", "red", 1) .put("apple", "green", 2) .put("banana", "yellow", 3) .build(); // 输出整个表格 System.out.println("ImmutableTable: " + table); // 获取某个键对应的行映射 Map<String, Integer> appleRow = table.row("apple"); System.out.println("Apple row: " + appleRow); // 获取某个列对应的映射 Map<String, Integer> redColumn = table.column("red"); System.out.println("Red column: " + redColumn); // 获取某个具体的值 Integer valueOfAppleRed = table.get("apple", "red"); System.out.println("Value of apple red: " + valueOfAppleRed); // 判断是否包含某个键值对 boolean containsAppleGreen = table.contains("apple", "green"); System.out.println("Contains apple green: " + containsAppleGreen); // 尝试修改(注意:这会失败,因为ImmutableTable是不可变的) // table.put("apple", "red", 42); // 这行代码会导致编译错误 } }
请注意,在上面的例子中,ImmutableTable.copyOf 方法实际上并不直接存在于 Guava 库中。相反,你应该使用 Tables.immutableTable 方法,但这个方法接受的是一个已经存在的表格,并返回一个不可变的视图。然而,由于 Guava 没有直接提供一个简单的方法来创建一个全新的不可变表格,通常的做法是先创建一个可变的表格,然后将其转换为一个不可变的视图。
7. ImmutableBiMap
表示不可变的、双向映射的集合。它同时提供了键到值和值到键的映射关系,并且保证了键和值的唯一性。与 ImmutableMap 类似,它也不允许添加、删除或更改映射关系。
import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableBiMap.Builder; public class ImmutableBiMapExample { public static void main(String[] args) { // 使用 Builder 创建 ImmutableBiMap Builder<String, Integer> builder = ImmutableBiMap.builder(); builder.put("one", 1); builder.put("two", 2); builder.put("three", 3); ImmutableBiMap<String, Integer> biMap = builder.build(); // 输出整个双向映射 System.out.println("ImmutableBiMap: " + biMap); // 通过键获取值 Integer valueOne = biMap.get("one"); System.out.println("Value for 'one': " + valueOne); // 通过值获取键(这是 BiMap 的特点) String keyForValueTwo = biMap.inverse().get(2); System.out.println("Key for value 2: " + keyForValueTwo); // 尝试修改(注意:这会失败,因为 ImmutableBiMap 是不可变的) // biMap.put("four", 4); // 这行代码会导致编译错误 // 尝试使用已存在的值作为键进行插入(也会失败,因为值也必须唯一) // builder.put("four", 2); // 这同样会导致错误,即使你试图在 build() 之后再做 } }
在上面的示例中,我使用了 ImmutableBiMap.Builder 来构建一个 ImmutableBiMap 实例。这个双向映射允许你通过键来查找值,也可以通过值来查找键(使用 inverse() 方法)。由于 ImmutableBiMap 是不可变的,任何试图修改它的操作(如 put 方法)都会导致编译时错误。
请注意,在构建 ImmutableBiMap 之后,你不能再使用 builder 添加或修改条目,因为 builder 已经在 build() 调用时被消耗掉了。如果你需要另一个不同的 ImmutableBiMap,你必须创建一个新的 Builder 实例。
此外,ImmutableBiMap 保证键和值的唯一性,所以每个键映射到一个唯一的值,每个值也映射到一个唯一的键。这意味着你不能在 ImmutableBiMap 中有重复的键或值。
总结
这些不可变集合的 API 都具有相似的特点,即不允许修改集合内容,提供了线程安全的访问方式,并且在创建时就需要确定集合的元素。这些集合类型在 Guava 库中被广泛使用,可以帮助开发者编写更加健壮和可维护的代码。
需要注意的是,所有 Guava 不可变集合的实现都不接受 null 值。如果需要在不可变集合中使用 null,可以考虑使用 JDK 中的 Collections.unmodifiableXXX 方法。
以上是关于 Google Guava 不可变集合 API 的简要介绍,更多详细信息和用法可以参考 Guava 官方文档。