提升编程效率的利器: 解析Google Guava库之集合篇Immutable(一)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 提升编程效率的利器: 解析Google Guava库之集合篇Immutable(一)

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 官方文档。

相关文章
|
1月前
|
数据处理 开发者 Python
Python 高级编程:深入解析 CSV 文件读取
在Python中,读取CSV文件是数据处理的重要环节。本文介绍了两种高效方法:一是利用pandas库的`read_csv`函数,将CSV文件快速转换为DataFrame对象,便于数据操作;二是通过csv模块的`csv.reader`按行读取CSV内容。此外,还涉及了如何选取特定列、解析日期格式、跳过指定行以及分块读取大文件等高级技巧,帮助开发者更灵活地处理各种CSV文件。参考链接:&lt;https://www.wodianping.com/app/2024-10/48782.html&gt;。
94 6
|
20天前
|
安全 程序员 API
|
16天前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####
|
16天前
|
设计模式 安全 Java
Java编程中的单例模式深入解析
【10月更文挑战第31天】在编程世界中,设计模式就像是建筑中的蓝图,它们定义了解决常见问题的最佳实践。本文将通过浅显易懂的语言带你深入了解Java中广泛应用的单例模式,并展示如何实现它。
|
27天前
|
Java 开发者 UED
Java编程中的异常处理机制解析
在Java的世界里,异常处理是确保程序稳定性和可靠性的关键。本文将深入探讨Java的异常处理机制,包括异常的类型、如何捕获和处理异常以及自定义异常的创建和使用。通过理解这些概念,开发者可以编写更加健壮和易于维护的代码。
|
1月前
|
Java 关系型数据库 MySQL
【编程基础知识】Eclipse连接MySQL 8.0时的JDK版本和驱动问题全解析
本文详细解析了在使用Eclipse连接MySQL 8.0时常见的JDK版本不兼容、驱动类错误和时区设置问题,并提供了清晰的解决方案。通过正确配置JDK版本、选择合适的驱动类和设置时区,确保Java应用能够顺利连接MySQL 8.0。
155 1
|
1月前
|
Java
【编程基础知识】《Java 基础探秘:return、break、continue、label、switch 与 enum 的深度解析》
本文深入解析了 Java 中的 return、break、continue、label、switch 和 enum 等基础概念,通过代码示例和流程图,帮助读者理解这些控制结构和枚举类型在编程中的应用,提升编程能力。
25 3
|
1月前
|
Java
【编程基础知识】《Java 中的神秘利器:this 关键字深度解析》
《Java 中的神秘利器:this 关键字深度解析》深入探讨了 Java 中 this 关键字的作用、用法及应用场景。文章详细解释了 this 如何指向当前对象、区分成员变量和局部变量、调用构造函数、实现方法链式调用和传递当前对象。通过阅读本文,读者将全面掌握 this 关键字的巧妙应用,提升 Java 编程技能。
30 2
|
1月前
|
开发框架 Oracle Java
【编程基础知识】《Java 世界探秘:JRE、JDK 与 JDK 版本全解析》
JRE(Java Runtime Environment)是运行Java程序所需的环境,包含JVM和Java核心类库,适合普通用户使用。JDK(Java Development Kit)则是Java开发工具包,不仅包含JRE,还提供了编译器、调试器等开发工具,适用于开发者。两者的主要区别在于JDK用于开发,而JRE仅用于运行Java程序。JDK各版本不断引入新特性,如Java 8中的Lambda表达式和默认方法等。环境配置方面,Windows和Linux系统都有详细的步骤,确保Java程序能够顺利编译和运行。
38 1
|
23天前
|
设计模式 SQL 安全
Java编程中的单例模式深入解析
【10月更文挑战第24天】在软件工程中,单例模式是设计模式的一种,它确保一个类只有一个实例,并提供一个全局访问点。本文将探讨如何在Java中使用单例模式,并分析其优缺点以及适用场景。
12 0

热门文章

最新文章

推荐镜像

更多
下一篇
无影云桌面