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

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 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 官方文档。

相关文章
|
2月前
|
缓存 Java 调度
Java并发编程:深入解析线程池与Future任务
【7月更文挑战第9天】线程池和Future任务是Java并发编程中非常重要的概念。线程池通过重用线程减少了线程创建和销毁的开销,提高了资源利用率。而Future接口则提供了检查异步任务状态和获取任务结果的能力,使得异步编程更加灵活和强大。掌握这些概念,将有助于我们编写出更高效、更可靠的并发程序。
|
1月前
|
测试技术 开发者 Python
Python 编程中的装饰器深入解析
【8月更文挑战第1天】本文将通过实例和代码演示,深入探讨 Python 中装饰器的概念、用法和高级应用。我们将从基础开始,逐步过渡到如何自定义装饰器,并展示其在日志记录、性能测试等场景下的实际用途。文章最后还将讨论装饰器的常见误区和最佳实践。
|
15天前
|
SQL 设计模式 安全
Java编程中的单例模式深入解析
【8月更文挑战第27天】本文旨在探索Java中实现单例模式的多种方式,并分析其优缺点。我们将通过代码示例,展示如何在不同的场景下选择最合适的单例模式实现方法,以及如何避免常见的陷阱。
|
4天前
|
存储 JSON API
Python编程:解析HTTP请求返回的JSON数据
使用Python处理HTTP请求和解析JSON数据既直接又高效。`requests`库的简洁性和强大功能使得发送请求、接收和解析响应变得异常简单。以上步骤和示例提供了一个基础的框架,可以根据你的具体需求进行调整和扩展。通过合适的异常处理,你的代码将更加健壮和可靠,为用户提供更加流畅的体验。
21 0
|
11天前
|
数据库 Windows
超详细步骤解析:从零开始,手把手教你使用 Visual Studio 打造你的第一个 Windows Forms 应用程序,菜鸟也能轻松上手的编程入门指南来了!
【8月更文挑战第31天】创建你的第一个Windows Forms (WinForms) 应用程序是一个激动人心的过程,尤其适合编程新手。本指南将带你逐步完成一个简单WinForms 应用的开发。首先,在Visual Studio 中创建一个“Windows Forms App (.NET)”项目,命名为“我的第一个WinForms 应用”。接着,在空白窗体中添加一个按钮和一个标签控件,并设置按钮文本为“点击我”。然后,为按钮添加点击事件处理程序`button1_Click`,实现点击按钮后更新标签文本为“你好,你刚刚点击了按钮!”。
30 0
|
11天前
|
开发者 编解码
界面适应奥秘:从自适应布局到图片管理,Xamarin响应式设计全解析
【8月更文挑战第31天】在 Xamarin 的世界里,构建灵活且适应性强的界面是每位开发者的必修课。本文将带您探索 Xamarin 的响应式设计技巧,包括自适应布局、设备服务协商和高效图片管理,帮助您的应用在各种设备上表现出色。通过 Grid 和 StackLayout 实现弹性空间分配,利用 Device 类检测设备类型以加载最优布局,以及使用 Image 控件自动选择合适图片资源,让您轻松应对不同屏幕尺寸的挑战。掌握这些技巧,让您的应用在多变的市场中持续领先。
19 0
|
11天前
|
设计模式 安全 Java
Java编程中的单例模式深度解析
【8月更文挑战第31天】 单例模式,作为设计模式中的经典之一,在Java编程实践中扮演着重要的角色。本文将通过简洁易懂的语言,逐步引导读者理解单例模式的本质、实现方法及其在实际应用中的重要性。从基础概念出发,到代码示例,再到高级应用,我们将一起探索这一模式如何优雅地解决资源共享和性能优化的问题。
|
12天前
|
存储 开发者 Ruby
【揭秘Ruby高手秘籍】OOP编程精髓全解析:玩转类、继承与多态,成就编程大师之路!
【8月更文挑战第31天】面向对象编程(OOP)是通过“对象”来设计软件的编程范式。Ruby作为一种纯面向对象的语言,几乎所有事物都是对象。本文通过具体代码示例介绍了Ruby中OOP的核心概念,包括类与对象、继承、封装、多态及模块混合,展示了如何利用这些技术更好地组织和扩展代码。例如,通过定义类、继承关系及私有方法,可以创建具有特定行为的对象,并实现灵活的方法重写和功能扩展。掌握这些概念有助于提升代码质量和可维护性。
21 0
|
1月前
|
开发者 Python
Python编程中的装饰器深度解析
【8月更文挑战第2天】装饰器在Python中是一种强大的工具,它允许我们在不修改原函数代码的情况下增加函数的功能。本文将深入探讨Python装饰器的工作原理,并通过实际的代码示例展示如何创建和应用装饰器。我们将从基础的装饰器概念出发,逐步过渡到更复杂的使用场景,包括带参数的装饰器和嵌套装饰器。无论你是初学者还是有经验的开发者,这篇文章都将帮助你更好地理解和利用Python装饰器来提升你的代码效率和可读性。
13 1
|
2月前
|
存储 数据库 Android开发
🔥Android Jetpack全解析!拥抱Google官方库,让你的开发之旅更加顺畅无阻!🚀
【7月更文挑战第28天】在Android开发中追求高效稳定的路径?Android Jetpack作为Google官方库集合,是你的理想选择。它包含多个独立又协同工作的库,覆盖UI到安全性等多个领域,旨在减少样板代码,提高开发效率与应用质量。Jetpack核心组件如LiveData、ViewModel、Room等简化了数据绑定、状态保存及数据库操作。引入Jetpack只需在`build.gradle`中添加依赖。例如,使用Room进行数据库操作变得异常简单,从定义实体到实现CRUD操作,一切尽在掌握之中。拥抱Jetpack,提升开发效率,构建高质量应用!
49 4

热门文章

最新文章

推荐镜像

更多