Guava新集合之Table

本文深入探讨Guava集合库中Table、ClassToInstanceMap、RangeSet和RangeMap的使用方法及特性,通过实例演示如何利用这些高级数据结构优化代码。

  https://www.cnblogs.com/peida/p/3183505.html

Table

  当我们需要多个索引的数据结构的时候,通常情况下,我们只能用这种丑陋的Map<FirstName, Map<LastName, Person>>来实现。为此Guava提供了一个新的集合类型-Table集合类型,来支持这种数据结构的使用场景。Table支持“row”和“column”,而且提供多种视图。 

复制代码

@Test
    public void TableTest(){
        Table<String, Integer, String> aTable = HashBasedTable.create();  
 
        for (char a = 'A'; a <= 'C'; ++a) {  
            for (Integer b = 1; b <= 3; ++b) {   
                aTable.put(Character.toString(a), b, String.format("%c%d", a, b));  
            }  
        }  
   
        System.out.println(aTable.column(2));  
        System.out.println(aTable.row("B"));   
        System.out.println(aTable.get("B", 2));  

        System.out.println(aTable.contains("D", 1));   
        System.out.println(aTable.containsColumn(3));   
        System.out.println(aTable.containsRow("C"));  
        System.out.println(aTable.columnMap()); 
        System.out.println(aTable.rowMap());   

        System.out.println(aTable.remove("B", 3)); 
    }

复制代码

  输出:

复制代码

{A=A2, B=B2, C=C2}
{1=B1, 2=B2, 3=B3}
B2
false
true
true
{1={A=A1, B=B1, C=C1}, 2={A=A2, B=B2, C=C2}, 3={A=A3, B=B3, C=C3}}
{A={1=A1, 2=A2, 3=A3}, B={1=B1, 2=B2, 3=B3}, C={1=C1, 2=C2, 3=C3}}
B3

复制代码

  Table视图:
  rowMap()返回一个Map<R, Map<C, V>>的视图。rowKeySet()类似地返回一个Set<R>。
  row(r)返回一个非null的Map<C, V>。修改这个视图Map也会导致原表格的修改。
  和列相关的方法有columnMap(), columnKeySet()和column(c)。(基于列的操作会比基于行的操作效率差些)
  cellSet()返回的是以Table.Cell<R, C, V>为元素的Set。这里的Cell就类似Map.Entry,但是它是通过行和列来区分的。

  Table有以下实现:
  HashBasedTable:基于HashMap<R, HashMap<C, V>>的实现。
  TreeBasedTable:基于TreeMap<R, TreeMap<C, V>>的实现。
  ImmutableTable:基于ImmutableMap<R, ImmutableMap<C, V>>的实现。(注意,ImmutableTable已对稀疏和密集集合做了优化)
  ArrayTable:ArrayTable是一个需要在构建的时候就需要定下行列的表格。这种表格由二维数组实现,这样可以在密集数据的表格的场合,提高时间和空间的效率。

  ClassToInstanceMap

  有的时候,你的map的key并不是一种类型,他们是很多类型,你想通过映射他们得到这种类型,guava提供了ClassToInstanceMap满足了这个目的。
  除了继承自Map接口,ClassToInstaceMap提供了方法 T getInstance(Class<T>) 和 T putInstance(Class<T>, T),消除了强制类型转换。
  该类有一个简单类型的参数,通常称为B,代表了map控制的上层绑定,例如:

ClassToInstanceMap<Number> numberDefaults = MutableClassToInstanceMap.create();
numberDefaults.putInstance(Integer.class, Integer.valueOf(0));

  从技术上来说,ClassToInstanceMap<B> 实现了Map<Class<? extends B>, B>,或者说,这是一个从B的子类到B对象的映射,这可能使得ClassToInstanceMap的泛型轻度混乱,但是只要记住B总是Map的上层绑定类型,通常来说B只是一个对象。
  guava提供了有用的实现, MutableClassToInstanceMap 和 ImmutableClassToInstanceMap.
  重点:像其他的Map<Class,Object>,ClassToInstanceMap 含有的原生类型的项目,一个原生类型和他的相应的包装类可以映射到不同的值;

复制代码

import org.junit.Test;

import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.MutableClassToInstanceMap;

public class OtherTest {
    
    @Test
    public  void ClassToInstanceMapTest() {
        ClassToInstanceMap<String> classToInstanceMapString =MutableClassToInstanceMap.create();
        ClassToInstanceMap<Person> classToInstanceMap =MutableClassToInstanceMap.create();
        Person person= new Person("peida",20);
        System.out.println("person name :"+person.name+" age:"+person.age);
        classToInstanceMapString.put(String.class, "peida");
        System.out.println("string:"+classToInstanceMapString.getInstance(String.class));
        
        classToInstanceMap.putInstance(Person.class,person);
        Person person1=classToInstanceMap.getInstance(Person.class);
        System.out.println("person1 name :"+person1.name+" age:"+person1.age);
    }
}

class Person {
    public String name;
    public int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
} 

复制代码

  RangeSet

  RangeSet用来处理一系列不连续,非空的range。当添加一个range到一个RangeSet之后,任何有连续的range将被自动合并,而空的range将被自动去除。例如:

复制代码

    @Test
    public void RangeSetTest(){
        RangeSet<Integer> rangeSet = TreeRangeSet.create();
        rangeSet.add(Range.closed(1, 10));
        System.out.println("rangeSet:"+rangeSet);
        rangeSet.add(Range.closedOpen(11, 15)); 
        System.out.println("rangeSet:"+rangeSet);
        rangeSet.add(Range.open(15, 20));
        System.out.println("rangeSet:"+rangeSet);
        rangeSet.add(Range.openClosed(0, 0)); 
        System.out.println("rangeSet:"+rangeSet);
        rangeSet.remove(Range.open(5, 10)); 
        System.out.println("rangeSet:"+rangeSet);
    }

复制代码

复制代码

输出:
rangeSet:{[1‥10]}
rangeSet:{[1‥10][11‥15)}
rangeSet:{[1‥10][11‥15)(15‥20)}
rangeSet:{[1‥10][11‥15)(15‥20)}
rangeSet:{[1‥5][10‥10][11‥15)(15‥20)}

复制代码

  注意,像合并Range.closed(1, 10)和Range.closedOpen(11, 15)这样的情况,我们必须先用调用Range.canonical(DiscreteDomain)传入DiscreteDomain.integers()处理一下。

  RangeSet的视图
  RangeSet的实现支持了十分丰富的视图,包括:
  complement():是个辅助的RangeSet,它本身就是一个RangeSet,因为它包含了非连续,非空的range。
  subRangeSet(Range<C>): 返回的是一个交集的视图。
  asRanges():返回可以被迭代的Set<Range<C>>的视图。
  asSet(DiscreteDomain<C>) (ImmutableRangeSet only):返回一个ImmutableSortedSet<C>类型的视图,里面的元素是range里面的元素,而不是range本身。(如果DiscreteDomain和RangeSet的上限或下限是无限的话,这个操作就不能支持)

  Queries
  除了支持各种视图,RangeSet还支持各种直接的查询操作,其中最重要的是:
  contains(C):这是RangeSet最基本的操作,它能查询给定的元素是否在RangeSet里。
  rangeContaining(C): 返回包含给定的元素的Range,如果不存在就返回null。
  encloses(Range<C>): 用来判断给定的Range是否包含在RangeSet里面。
  span():返回一个包含在这个RangeSet的所有Range的并集。

  RangeMap
  RangeMap代表了非连续非空的range对应的集合。不像RangeSet,RangeMap不会合并相邻的映射,甚至相邻的range对应的是相同的值。例如:

复制代码

    @Test
    public void RangeMapTest(){
        RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
         rangeMap.put(Range.closed(1, 10), "foo"); 
         System.out.println("rangeMap:"+rangeMap);
         rangeMap.put(Range.open(3, 6), "bar"); 
         System.out.println("rangeMap:"+rangeMap);
         rangeMap.put(Range.open(10, 20), "foo"); 
         System.out.println("rangeMap:"+rangeMap);
         rangeMap.remove(Range.closed(5, 11)); 
         System.out.println("rangeMap:"+rangeMap);
    }

    输出:
    rangeMap:[[1‥10]=foo]
    rangeMap:[[1‥3]=foo, (3‥6)=bar, [6‥10]=foo]
    rangeMap:[[1‥3]=foo, (3‥6)=bar, [6‥10]=foo, (10‥20)=foo]
    rangeMap:[[1‥3]=foo, (3‥5)=bar, (11‥20)=foo]

复制代码

  RangeMap的视图
  RangeMap提供了两种视图:
  asMapOfRanges():返回Map<Range<K>, V>类型的视图。这个操作可以被用作迭代操作。
  subRangeMap(Range<K>)提供给定Range的交集。这个操作可以推广到传统的headMap, subMap, 和tailMap。

<think> 嗯,用户想了解Guava库中的集合类信息。从对话历史看,用户已经提供了一些引用片段作为背景资料,我需要整理这些信息并给出系统化的解答。 用户提供的引用很有价值:引用[1]和[2]分别提到Sets和Lists工具类,引用[3]则概述了Guava集合工具的整体框架,包括Lists/Sets/Maps三大核心工具类,以及Iterables、Ordering等扩展功能。引用[4]展示了与Java标准集合创建的对比,引用[5]则提到RangeMap这种特殊集合。 用户的核心需求很明确——希望系统了解Guava集合类的体系。我会从三个层面组织回答:首先是核心工具类(Lists/Sets/Maps),其次是功能扩展类(Iterables/Ordering等),最后是特殊集合类型(RangeSet/EvictingQueue)。需要特别注意两点:一是强调Guava相比Java标准库的优势(如不可变集合、流式操作),二是用具体代码示例说明用法,比如引用[4]展示的简洁创建方式就很直观。 在回答结构上,考虑先总述Guava集合工具的价值(如引用[3]所说"增强功能性和易用性"),再分模块详解。对于特殊集合类型,要说明适用场景,比如RangeMap适合区间映射的场景。最后准备的相关问题可以引导用户深入了解特定工具类或性能优化实践。 值得注意的细节:不可变集合的线程安全特性要重点说明,RangeSet/RangeMap的非合并特性(引用[5])容易产生误解需要澄清,EvictingQueue的自动驱逐机制也很实用。代码示例采用Java但保持简洁,避免过多语法细节干扰主干认知。 </think> 好的,我们来详细介绍 Google Guava 库中的集合类(Collections)。Guava 极大地扩展了 Java 标准集合框架(Java Collections Framework, JCF),提供了更强大、更易用、更高效的集合操作工具和集合类型。 Guava集合工具主要体现在以下几个方面: 1. **核心工具类 (Utility Classes):** * **`Lists`**: 专注于 `List` 及其子类的实用操作。 * **创建:** 提供比 `new ArrayList<>()` 更简洁的方式创建可变 (`newArrayList()`) 和不可变 (`immutableListOf()`, `copyOf()`) 列表。例如: ```java List<String> names = Lists.newArrayList("Alice", "Bob", "Charlie"); // 可变 ImmutableList<String> fixedNames = ImmutableList.of("Alpha", "Beta", "Gamma"); // 不可变 ``` * **转换:** `transform(list, function)` 对列表每个元素应用函数生成列表。 * **分区/分块:** `partition(list, size)` 将大列表分割成指定大小的子列表。 * **反转:** `reverse(list)` 返回列表的反转视图。 * **字符处理:** `charactersOf(string)` 将字符串视为字符列表。 * **`Sets`**: 专注于 `Set` 及其子类的实用操作。[^1] * **创建:** 提供 `newHashSet()`, `newLinkedHashSet()`, `newTreeSet()`, `immutableSetOf()`, `copyOf()` 等。 * **集合运算:** 核心价值所在! * `union(set1, set2)`:并集。 * `intersection(set1, set2)`:交集。 * `difference(set1, set2)`:差集(属于 set1 但不属于 set2)。 * `symmetricDifference(set1, set2)`:对称差集(仅在其中一个集合中的元素)。 * **过滤:** `filter(set, predicate)` 返回满足条件的元素子集视图。 * **笛卡尔积:** `cartesianProduct(set1, set2, ...)` 返回多个集合的笛卡尔积。 * **`Maps`**: 专注于 `Map` 及其子类的实用操作。 * **创建:** `newHashMap()`, `newLinkedHashMap()`, `newTreeMap()`, `immutableMapOf()`, `copyOf()` 等。 * **转换:** `transformValues(map, function)` 对 Map 的每个值应用函数生成 Map 视图;`transformEntries(map, function)` 转换键值对。 * **过滤:** `filterKeys(map, predicate)`, `filterValues(map, predicate)`, `filterEntries(map, predicate)`。 * **唯一索引:** `uniqueIndex(iterable, keyFunction)` 根据元素属性生成键唯一的 Map。 * **差值:** `difference(map1, map2)` 比较两个 Map 的差异(键值对的增删改)。 * **`BiMap` 工具:** 提供操作双向映射的工具。 2. **功能增强工具类 (Enhanced Utilities):** * **`Iterables` / `Iterators`**: 提供通用、强大的操作,适用于任何实现了 `Iterable` 或 `Iterator` 接口的对象,包括标准集合和自定义集合。[^3] * **链式操作:** `filter(iterable, predicate)`, `transform(iterable, function)`, `concat(iterable...)` 连接多个可迭代对象, `limit(iterable, maxSize)`, `skip(iterable, number)`, `cycle(iterable)` 循环迭代。 * **查找与判断:** `contains(iterable, element)`, `frequency(iterable, element)`, `any(iterable, predicate)`, `all(iterable, predicate)`, `find(iterable, predicate)`, `getFirst(iterable, default)`, `getLast(iterable, default)`。 * **分组:** `groupBy(iterable, keyFunction)` 根据键函数分组元素。 * **批量操作:** `addAll(collection, iterable)` 高效添加。 * **元素计数:** `size(iterable)` 高效计算元素个数(尽可能避免遍历)。 * **`Ordering`**: Guava 强大的流畅比较器 (`Comparator`) 实现框架。[^3] * **创建:** `natural()` (自然顺序), `usingToString()` (toString 顺序), `from(comparator)` (包装现有比较器), `explicit(values)` (指定固定顺序)。 * **链式调用:** `reverse()`, `nullsFirst()`, `nullsLast()`, `compound(secondaryComparator)`(主比较器相同时使用次比较器),`onResultOf(function)`(先对元素应用函数再比较)。 * **操作集合:** `greatestOf(iterable, k)` 获取最大的 k 个元素,`isOrdered(iterable)` 检查是否有序,`sortedCopy(iterable)`, `immutableSortedCopy(iterable)`。 ```java Ordering<Person> ordering = Ordering.natural().onResultOf(Person::getAge) // 按年龄升序 .nullsLast() // 将年龄为null的排到最后 .compound(Ordering.natural().onResultOf(Person::getName)); // 年龄相同按姓名升序 List<Person> sortedPeople = ordering.immutableSortedCopy(people); ``` 3. **集合类型 (New Collection Types):** * **不可变集合 (`ImmutableList`, `ImmutableSet`, `ImmutableMap`, `ImmutableXXX`):** [^3][^4] * **核心特性:** 创建后内容绝对不可修改(线程安全、内存效率高、可作为常量安全使用)。 * **创建方式:** 使用 `of()`, `copyOf()`, `builder()` 模式。`ImmutableList.copyOf(someList)` 是常用方式。 * **优势:** 安全性、效率、防御式编程。 * **`Multiset`**: 可以统计元素出现次数的集合(像 `Bag` 或带计数的 `Set`)。 * **实现:** `HashMultiset`, `TreeMultiset`, `LinkedHashMultiset`, `ImmutableMultiset`。 * **核心方法:** `count(element)` 获取元素计数,`add(element, occurrences)`, `remove(element, occurrences)`, `elementSet()` 获取唯一元素集。 * **`Multimap`**: 一个键可以映射到多个值的映射(类似 `Map<K, List<V>>` 或 `Map<K, Set<V>>`,但更易用)。 * **实现:** `ArrayListMultimap` (值存储在 `ArrayList` 中), `HashMultimap` (值存储在 `HashSet` 中), `LinkedListMultimap` (保留插入顺序), `TreeMultimap` (键和值排序), `ImmutableMultimap`。 * **核心方法:** `put(key, value)`, `get(key)` 返回值的集合(不是单个值!),`containsKey(key)`, `containsEntry(key, value)`, `remove(key, value)`, `removeAll(key)`, `replaceValues(key, values)`。 * **`BiMap` (双向映射):** 保证键和值都是唯一的,提供了 `inverse()` 方法来获取值到键的反向视图。 * **实现:** `HashBiMap`, `EnumBiMap`, `EnumHashBiMap`, `ImmutableBiMap`。 * **核心约束:** `put(key, value)` 时,如果值已存在(即使对应不同的键)会抛出 `IllegalArgumentException`。可使用 `forcePut(key, value)` 强制替换(慎用)。 * **`Table`**: 类似于有两个键(行键和列键)的映射(类似 `Map<RowKey, Map<ColumnKey, Value>>`)。 * **实现:** `HashBasedTable`, `TreeBasedTable`, `ArrayTable` (行列固定且已知时高效)。 * **核心方法:** `put(rowKey, columnKey, value)`, `get(rowKey, columnKey)`, `row(rowKey)` 返回对应行的 `Map<ColumnKey, Value>`, `column(columnKey)` 返回对应列的 `Map<RowKey, Value>`。 * **`RangeSet` / `RangeMap`**: 处理区间(`Range`)的集合。[^5] * **`RangeSet`**: 表示一组不相交、非空的区间集合。支持高效的区间查询(`contains(value)`, `encloses(range)`)和区间操作(`add(range)`, `remove(range)`, `complement()` 补集)。 * **`RangeMap`**: 将不相交、非空的区间(`Range`)映射到某个值。查询一个点落在哪个区间(`get(key)`)或者哪个区间包含某个值(`getEntry(key)`)非常高效。**_不会合并相邻但映射值相同的区间_**。[^5] ```java RangeMap<Integer, String> gradeRange = TreeRangeMap.create(); gradeRange.put(Range.closed(90, 100), "A"); gradeRange.put(Range.closedOpen(80, 90), "B"); // 80 <= score < 90 gradeRange.put(Range.closedOpen(70, 80), "C"); String grade = gradeRange.get(85); // 返回 "B" ``` * **`EvictingQueue`**: 一种定长的、具有自动驱逐功能的队列。[^3] * **特性:** 当队列满时,再添加元素会导致队列头部的元素被自动移除(先进先出淘汰)。 * **创建:** `EvictingQueue.create(maxSize)`。 * **适用场景:** 实现简单的滑动窗口、缓存、最近 N 项记录等。 **总结:** Guava集合部分是其最核心、最常用的模块之一。它通过: 1. **工具类 (`Lists`, `Sets`, `Maps`, `Iterables`, `Iterators`, `Ordering`):** 极大地简化了标准集合的创建、转换、过滤、运算(尤其是 Sets)和排序操作,代码更简洁高效。 2. **不可变集合:** 提供安全、高效、线程安全的常量集合实现。 3. **集合 (`Multiset`, `Multimap`, `BiMap`, `Table`, `RangeSet`, `RangeMap`, `EvictingQueue`):** 引入了标准库中没有的、但实践中非常实用的数据结构,解决了特定场景下的复杂需求(如计数、一对多映射、双向映射、二维表、区间查询、固定大小缓存队列等)。 使用 Guava 集合工具类和集合类型,可以显著提升 Java 代码在处理集合数据时的可读性、简洁性和性能。[^1][^2][^3][^4][^5]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值