提升编程效率的利器: 解析Google Guava库之集合工具类-50个示例(八)

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

在软件开发中,集合是处理数据的一种基本且关键的数据结构。Java作为一种广泛使用的编程语言,提供了一套丰富的集合工具类,这些工具类可以极大地提升我们处理集合数据的效率。本文将深入探讨Java集合工具类的使用,帮助您更好地利用这些工具优化代码


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

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

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

提升编程效率的利器: 解析Google Guava库之集合篇Table二维映射(四)

提升编程效率的利器: 解析Google Guava库之集合篇RangeSet范围集合(五)

提升编程效率的利器: 解析Google Guava库之集合篇RangeMap范围映射(六)

提升编程效率的利器: 解析Google Guava库之常用工具类-40个示例(七)


Guava库为Java的集合处理提供了一套全面且强大的工具类,极大地增强了Java集合框架的功能性和易用性。

其中,Lists、Sets和Maps工具类简化了不可变集合的创建和常见操作,同时提供了集合转换、过滤、合并等高级功能。

Iterables和Iterators工具类则扩展了迭代处理的能力,允许在迭代过程中进行流式处理,如元素转换和过滤。

Ordering工具类引入了一个强大的比较器框架,支持自然排序、自定义排序和链式比较,为复杂排序需求提供了灵活解决方案。

而EvictingQueue工具类实现了一种具有自动驱逐功能的队列,有效控制了缓存或队列的内存使用。

一、Lists的使用

Lists 是一个提供静态工具方法来操作或创建 List 实例的类。

  • 它包括用于创建不可变列表、将数组转换为列表、分割列表等的方法。
import com.google.common.collect.Lists;  
import java.util.ArrayList;  
import java.util.Arrays;  
import java.util.Collections;  
import java.util.Comparator;  
import java.util.List;  
  
public class GuavaListsExampleContinued {  
  
    public static void main(String[] args) {  
        // 创建一个ArrayList  
        List<String> fruits = new ArrayList<>(Arrays.asList("apple", "banana", "cherry", "date"));  
  
        // 使用Lists.asList将数组转换为不可变的List  
        List<String> immutableFruits = Lists.asList("grape", "lemon");  
        // 注意:尝试修改immutableFruits将抛出UnsupportedOperationException  
        // immutableFruits.add("orange"); // This line will throw an exception  
  
        // 输出immutableFruits列表  
        // 输出:[grape, lemon]  
        System.out.println(immutableFruits);  
  
        // 使用Lists.concatenate将多个列表连接成一个列表  
        List<String> moreFruits = new ArrayList<>(Arrays.asList("mango", "melon"));  
        List<String> allFruits = Lists.newArrayList(Lists.concatenate(fruits, moreFruits));  
        // 输出:[apple, banana, cherry, date, mango, melon]  
        System.out.println(allFruits);  
  
        // 使用Lists.getOrDefault获取列表中的元素,如果索引越界则返回默认值  
        String fruitAtIndex = Lists.getOrDefault(fruits, 2, "default");  
        // 输出:cherry  
        System.out.println(fruitAtIndex);  
  
        // 尝试获取一个不存在的索引,返回默认值  
        String fruitAtInvalidIndex = Lists.getOrDefault(fruits, 10, "default");  
        // 输出:default  
        System.out.println(fruitAtInvalidIndex);  
  
        // 使用Lists.newLinkedList创建一个新的LinkedList  
        List<String> linkedList = Lists.newLinkedList(fruits);  
        // 输出:[apple, banana, cherry, date]  
        System.out.println(linkedList);  
  
        // 使用Lists.newCopyOnWriteArrayList创建一个新的线程安全的CopyOnWriteArrayList  
        List<String> threadSafeList = Lists.newCopyOnWriteArrayList(fruits);  
        // 输出:[apple, banana, cherry, date]  
        System.out.println(threadSafeList);  
  
        // 注意:CopyOnWriteArrayList在并发修改时提供了更好的可见性,但写入操作的成本较高。  
  
        // 使用Lists.subList获取列表的子列表  
        List<String> subList = fruits.subList(1, 3); // 包含开始索引,不包含结束索引  
        // 输出:[banana, cherry]  
        System.out.println(subList);  
  
        // 注意:此处的subList方法实际上是java.util.List接口的方法,不是Guava特有的,但在此处一并演示。  
  
        // 使用Lists.setDifference获取两个列表之间的差集  
        List<String> list1 = Arrays.asList("a", "b", "c", "d");  
        List<String> list2 = Arrays.asList("b", "c");  
        List<String> difference = Lists.newArrayList(Lists.setDifference(list1, list2));  
        // 输出:[a, d]  
        System.out.println(difference);  
  
        // 注意:setDifference方法返回的是两个列表中第一个列表有而第二个列表没有的元素,且结果不保证顺序。  
  
        // 使用Lists.newArrayListWithExpectedSize创建一个具有预期大小的ArrayList  
        List<String> expectedSizeList = Lists.newArrayListWithExpectedSize(10);  
        // 添加元素以展示其容量  
        for (int i = 0; i < 10; i++) {  
            expectedSizeList.add("item" + i);  
        }  
        // 输出:[item0, item1, item2, item3, item4, item5, item6, item7, item8, item9]  
        System.out.println(expectedSizeList);  
  
        // 注意:newArrayListWithExpectedSize方法创建的ArrayList会根据预期大小进行初始化,以提高性能。  
    }  
}

二、Sets的使用

Sets 提供了用于操作 Set 的静态方法。

  • 它允许你创建不可变的集合、合并多个集合、过滤集合中的元素等。
import com.google.common.collect.Sets;  
import java.util.Arrays;  
import java.util.HashSet;  
import java.util.Set;  
  
public class GuavaSetsExample {  
  
    public static void main(String[] args) {  
        // 创建一个HashSet并添加元素  
        Set<String> colors = new HashSet<>(Arrays.asList("red", "green", "blue"));  
  
        // 使用Sets.immutableEnumSet创建一个不可修改的EnumSet  
        Set<DayOfWeek> weekdays = Sets.immutableEnumSet(DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY);  
        // 输出: [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY]  
        System.out.println(weekdays);  
  
        // 注意:尝试修改weekdays将抛出UnsupportedOperationException  
        // weekdays.add(DayOfWeek.SATURDAY); // This line will throw an exception  
  
        // 使用Sets.newHashSet创建一个新的HashSet  
        Set<String> newColors = Sets.newHashSet("yellow", "orange");  
        // 输出: [orange, yellow] (HashSet不保证顺序)  
        System.out.println(newColors);  
  
        // 使用Sets.union将多个集合合并为一个视图  
        Set<String> allColors = Sets.union(colors, newColors);  
        // 输出: [red, blue, green, orange, yellow] (不保证特定顺序)  
        System.out.println(allColors);  
  
        // 使用Sets.difference获取两个集合之间的差集  
        Set<String> difference = Sets.difference(colors, newColors);  
        // 输出: [red, blue, green] (不保证特定顺序)  
        System.out.println(difference);  
  
        // 使用Sets.intersection获取两个集合的交集  
        Set<String> intersection = Sets.intersection(colors, newColors);  
        // 输出: [] (因为没有交集,所以为空集)  
        System.out.println(intersection);  
  
        // 使用Sets.filter过滤集合中的元素  
        Set<String> filteredColors = Sets.filter(colors, color -> !color.equals("red"));  
        // 输出: [blue, green] (不保证特定顺序)  
        System.out.println(filteredColors);  
  
        // 使用Sets.cartesianProduct计算两个集合的笛卡尔积  
        Set<List<String>> cartesianProduct = Sets.cartesianProduct(Sets.newHashSet("A", "B"), Sets.newHashSet(1, 2));  
        // 输出: [[A, 1], [A, 2], [B, 1], [B, 2]] (不保证特定顺序)  
        System.out.println(cartesianProduct);  
  
        // 注意:cartesianProduct返回的是List<String>的集合,每个列表都包含来自输入集合的一个元素组合。  
  
        // 使用Sets.powerSet计算集合的所有可能子集  
        Set<Set<String>> powerSet = Sets.powerSet(Sets.newHashSet("a", "b", "c"));  
        // 输出: [[], [a], [b], [c], [a, b], [a, c], [b, c], [a, b, c]] (不保证特定顺序)  
        System.out.println(powerSet);  
  
        // 注意:powerSet方法返回的是集合的集合,它包含了输入集合的所有可能子集(包括空集和输入集合本身)。  
  
        // 使用Sets.newConcurrentHashSet创建一个线程安全的HashSet  
        Set<String> concurrentColors = Sets.newConcurrentHashSet(colors);  
        // 输出: [red, blue, green] (不保证特定顺序)  
        System.out.println(concurrentColors);  
  
        // 注意:newConcurrentHashSet方法创建的集合可以在多线程环境中安全使用。  
  
        // 使用Sets.newEnumSet创建一个指定元素类型的EnumSet  
        Set<DayOfWeek> weekend = Sets.newEnumSet(Arrays.asList(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY), DayOfWeek.class);  
        // 输出: [SATURDAY, SUNDAY]  
        System.out.println(weekend);  
  
        // 注意:EnumSet是一种高效的、类型安全的集合,它包含一组枚举常量。  
    }  
}  
  
// 假设存在一个名为DayOfWeek的枚举类型  
enum DayOfWeek {  
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY  
}

三、Maps的使用

Maps 包含操作 Map 的静态方法。

  • 你可以使用它来创建不可变的映射、过滤键或值、转换映射中的键或值等。
import com.google.common.collect.ImmutableMap;  
import com.google.common.collect.Maps;  
  
import java.util.HashMap;  
import java.util.Map;  
  
public class GuavaMapsExample {  
  
    public static void main(String[] args) {  
        // 创建一个HashMap并添加元素  
        Map<String, Integer> scores = new HashMap<>();  
        scores.put("Alice", 90);  
        scores.put("Bob", 85);  
        scores.put("Charlie", 95);  
  
        // 使用Maps.immutableMap创建一个不可修改的Map  
        ImmutableMap<String, Integer> immutableScores = ImmutableMap.copyOf(scores);  
        // 输出整个Map: {Alice=90, Bob=85, Charlie=95} (顺序可能不同)  
        System.out.println(immutableScores);  
  
        // 注意:尝试修改immutableScores将抛出UnsupportedOperationException  
        // immutableScores.put("David", 92); // This line will throw an exception  
  
        // 使用Maps.newHashMap创建一个新的HashMap  
        Map<String, String> names = Maps.newHashMap();  
        names.put("1", "Alice");  
        names.put("2", "Bob");  
        // 输出整个Map: {1=Alice, 2=Bob} (顺序可能不同)  
        System.out.println(names);  
  
        // 使用Maps.difference获取两个Map之间的差异  
        Map<String, Integer> scoreUpdates = Maps.newHashMap(scores);  
        scoreUpdates.put("Bob", 87); // 更新Bob的分数  
        scoreUpdates.put("David", 88); // 新增David的分数  
        Map<String, Integer> scoreDifferences = Maps.difference(scores, scoreUpdates).entriesDiffering();  
        // 输出有差异的键值对: {Bob=85} (只显示原始Map中存在但值已更改的键值对)  
        System.out.println(scoreDifferences);  
  
        // 使用Maps.filterKeys, Maps.filterValues, Maps.filterEntries过滤Map中的元素  
        Map<String, Integer> filteredScoresByKey = Maps.filterKeys(scores, key -> "Alice".equals(key) || "Charlie".equals(key));  
        // 输出过滤后的Map: {Alice=90, Charlie=95} (只包含指定键的条目,顺序可能不同)  
        System.out.println(filteredScoresByKey);  
  
        Map<String, Integer> filteredScoresByValue = Maps.filterValues(scores, value -> value > 90);  
        // 输出过滤后的Map: {Charlie=95} (只包含值大于90的条目,可能为空如果无满足条件)  
        System.out.println(filteredScoresByValue);  
  
        // 使用Maps.transformEntries对Map中的每个条目应用函数  
        Map<String, String> transformedScores = Maps.transformEntries(scores, (key, value) -> key + ": " + value);  
        // 输出转换后的Map: {Alice: 90=Alice: 90, Bob: 85=Bob: 85, Charlie: 95=Charlie: 95} (将每个条目转换为字符串形式,顺序可能不同)  
        // 注意:transformEntries返回的Map的values()视图会随源Map变化而变化,但keySet()和entrySet()不会  
        System.out.println(transformedScores);  
  
        // 使用Maps.uniqueIndex对集合中的元素进行唯一性索引  
        Map<Integer, String> indexedNames = Maps.uniqueIndex(names.entrySet(), entry -> entry.getValue().length());  
        // 输出按值长度索引的Map: {5=Alice, 3=Bob} (将名字按其长度作为键进行索引,如果有重复长度会抛出异常)  
        System.out.println(indexedNames);  
  
        // 注意:uniqueIndex假设提供的转换函数为每个输入产生唯一的输出。如果发现有重复,会抛出IllegalArgumentException。  
  
        // 在实际使用时,可能需要对上面的代码进行调整以避免潜在的异常或满足特定的业务需求。  
    }  
}

四、Iterables、Iterators、Ordering和EvictingQueue的使用

Iterables 提供了对 Iterable 实例进行操作的静态方法,而 Iterators 提供了对 Iterator 实例进行操作的静态方法。这些方法允许你在迭代过程中转换、过滤、合并或分割元素。

  • Ordering 是一个强大的“流畅风格比较器”。它扩展了Java的 Comparator 接口,提供了更丰富的比较和排序功能。你可以使用它来创建自然排序或自定义排序的比较器,还可以进行链式比较、复合比较等操作。
  • EvictingQueue 是一个具有自动驱逐最老元素的队列。
  • 当你向队列添加元素,并且队列的大小超过了其容量时,最老的元素(即最早添加的元素)会被自动移除。这对于缓存最近的元素或事件,同时限制内存使用非常有用。
import com.google.common.collect.*;  
import com.google.common.base.Function;  
import com.google.common.base.Preconditions;  
  
import java.util.Iterator;  
import java.util.List;  
  
public class GuavaCollectionsExample {  
  
    public static void main(String[] args) {  
        // 使用Iterables和Iterators操作集合  
        List<String> names = Lists.newArrayList("Alice", "Bob", "Charlie", "David");  
  
        // 使用Iterables.transform将集合中的元素转换为大写  
        Iterable<String> upperCaseNames = Iterables.transform(names, String::toUpperCase);  
        // 输出转换后的集合: [ALICE, BOB, CHARLIE, DAVID]  
        System.out.println(upperCaseNames); // 注意:此处打印的是Iterable视图,实际转换在迭代时发生  
  
        // 使用Iterables.filter筛选集合中以"A"开头的元素  
        Iterable<String> filteredNames = Iterables.filter(names, name -> name.startsWith("A"));  
        // 输出筛选后的集合: [Alice]  
        System.out.println(filteredNames); // 注意:此处打印的是Iterable视图,实际筛选在迭代时发生  
  
        // 使用Iterators.peekingIterator获取一个可以预先查看下一个元素的迭代器  
        Iterator<String> peekingIterator = Iterators.peekingIterator(names.iterator());  
        // 输出当前迭代器可查看的下一个元素,但不移动指针: Alice  
        System.out.println(peekingIterator.peek());  
        // 输出当前迭代器可查看的下一个元素,并移动指针: Alice  
        System.out.println(peekingIterator.next());  
  
        // 使用Ordering对集合进行排序  
        List<Integer> scores = Lists.newArrayList(90, 85, 95, 88);  
        Ordering<Integer> scoreOrdering = Ordering.natural();  
        // 输出排序后的集合: [85, 88, 90, 95]  
        List<Integer> sortedScores = scoreOrdering.sortedCopy(scores);  
        System.out.println(sortedScores);  
  
        // 使用Ordering的链式比较器  
        List<String> players = Lists.newArrayList("Alice_90", "Bob_85", "Charlie_95", "David_88");  
        Ordering<String> playerOrdering = Ordering.natural()  
                .onResultOf(new Function<String, Integer>() {  
                    @Override  
                    public Integer apply(String player) {  
                        String[] split = player.split("_");  
                        Preconditions.checkArgument(split.length == 2, "Player string should have name and score");  
                        return Integer.parseInt(split[1]);  
                    }  
                })  
                .reverse() // 按分数降序排列  
                .compound(Ordering.natural()); // 分数相同时按名称升序排列  
        // 输出排序后的集合: [Charlie_95, Alice_90, David_88, Bob_85]  
        List<String> sortedPlayers = playerOrdering.sortedCopy(players);  
        System.out.println(sortedPlayers);  
  
        // 使用EvictingQueue实现一个固定大小的队列  
        EvictingQueue<String> evictingQueue = EvictingQueue.create(3);  
        evictingQueue.add("Alice");  
        evictingQueue.add("Bob");  
        evictingQueue.add("Charlie");  
        // 输出当前队列中的元素: [Alice, Bob, Charlie]  
        System.out.println(evictingQueue);  
  
        evictingQueue.add("David"); // 这将导致Alice被移除  
        // 输出添加新元素后的队列: [Bob, Charlie, David]  
        System.out.println(evictingQueue);  
    }  
}

五、结语

Java集合工具类是处理集合数据的得力助手。通过深入了解和使用这些工具类,我们可以编写出更高效、更安全、更简洁的代码。希望本文能对您在Java编程中使用集合工具类有所帮助。

相关文章
|
27天前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
38 3
|
11天前
|
存储 Java 开发者
Java中的集合框架深入解析
【10月更文挑战第32天】本文旨在为读者揭开Java集合框架的神秘面纱,通过深入浅出的方式介绍其内部结构与运作机制。我们将从集合框架的设计哲学出发,探讨其如何影响我们的编程实践,并配以代码示例,展示如何在真实场景中应用这些知识。无论你是Java新手还是资深开发者,这篇文章都将为你提供新的视角和实用技巧。
12 0
|
1月前
|
存储 搜索推荐 数据库
运用LangChain赋能企业规章制度制定:深入解析Retrieval-Augmented Generation(RAG)技术如何革新内部管理文件起草流程,实现高效合规与个性化定制的完美结合——实战指南与代码示例全面呈现
【10月更文挑战第3天】构建公司规章制度时,需融合业务实际与管理理论,制定合规且促发展的规则体系。尤其在数字化转型背景下,利用LangChain框架中的RAG技术,可提升规章制定效率与质量。通过Chroma向量数据库存储规章制度文本,并使用OpenAI Embeddings处理文本向量化,将现有文档转换后插入数据库。基于此,构建RAG生成器,根据输入问题检索信息并生成规章制度草案,加快更新速度并确保内容准确,灵活应对法律与业务变化,提高管理效率。此方法结合了先进的人工智能技术,展现了未来规章制度制定的新方向。
34 3
|
30天前
|
前端开发 JavaScript UED
axios取消请求CancelToken的原理解析及用法示例
axios取消请求CancelToken的原理解析及用法示例
88 0
|
3月前
|
开发者 图形学 Java
揭秘Unity物理引擎核心技术:从刚体动力学到关节连接,全方位教你如何在虚拟世界中重现真实物理现象——含实战代码示例与详细解析
【8月更文挑战第31天】Unity物理引擎对于游戏开发至关重要,它能够模拟真实的物理效果,如刚体运动、碰撞检测及关节连接等。通过Rigidbody和Collider组件,开发者可以轻松实现物体间的互动与碰撞。本文通过具体代码示例介绍了如何使用Unity物理引擎实现物体运动、施加力、使用关节连接以及模拟弹簧效果等功能,帮助开发者提升游戏的真实感与沉浸感。
78 1
|
3月前
|
存储 算法 Java
Java中的集合框架深度解析云上守护:云计算与网络安全的协同进化
【8月更文挑战第29天】在Java的世界中,集合框架是数据结构的代言人。它不仅让数据存储变得优雅而高效,还为程序员提供了一套丰富的工具箱。本文将带你深入理解集合框架的设计哲学,探索其背后的原理,并分享一些实用的使用技巧。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇通往高效编程的大门。
|
3月前
|
JSON 前端开发 API
【淘系】商品详情属性解析(属性规格详情图sku等json数据示例返回参考),淘系API接口系列
在淘宝(或天猫)平台上,商品详情属性(如属性规格、详情图、SKU等)是商家在发布商品时设置的,用于描述商品的详细信息和不同规格选项。这些信息对于消费者了解商品特性、进行购买决策至关重要。然而,直接通过前端页面获取这些信息的结构化数据(如JSON格式)并非直接暴露给普通用户或开发者,因为这涉及到平台的商业机密和数据安全。 不过,淘宝平台提供了丰富的API接口(如淘宝开放平台API),允许有资质的开发者或合作伙伴通过编程方式获取商品信息。这些API接口通常需要注册开发者账号、申请应用密钥(App Key)和秘钥(App Secret),并遵守淘宝的API使用协议。
|
3月前
|
设计模式 存储 Java
掌握Java设计模式的23种武器(全):深入解析与实战示例
掌握Java设计模式的23种武器(全):深入解析与实战示例
|
3月前
|
机器学习/深度学习 运维 算法
深入探索机器学习中的支持向量机(SVM)算法:原理、应用与Python代码示例全面解析
【8月更文挑战第6天】在机器学习领域,支持向量机(SVM)犹如璀璨明珠。它是一种强大的监督学习算法,在分类、回归及异常检测中表现出色。SVM通过在高维空间寻找最大间隔超平面来分隔不同类别的数据,提升模型泛化能力。为处理非线性问题,引入了核函数将数据映射到高维空间。SVM在文本分类、图像识别等多个领域有广泛应用,展现出高度灵活性和适应性。
151 2
|
3月前
|
开发者 图形学 C#
揭秘游戏沉浸感的秘密武器:深度解析Unity中的音频设计技巧,从背景音乐到动态音效,全面提升你的游戏氛围艺术——附实战代码示例与应用场景指导
【8月更文挑战第31天】音频设计在游戏开发中至关重要,不仅能增强沉浸感,还能传递信息,构建氛围。Unity作为跨平台游戏引擎,提供了丰富的音频处理功能,助力开发者轻松实现复杂音效。本文将探讨如何利用Unity的音频设计提升游戏氛围,并通过具体示例代码展示实现过程。例如,在恐怖游戏中,阴森的背景音乐和突然的脚步声能增加紧张感;在休闲游戏中,轻快的旋律则让玩家感到愉悦。
84 0

推荐镜像

更多