1. 概述
本教程将介绍 Google Guava 库中的 Table
接口及其多种实现方式。
Guava 的 Table
是一种集合结构,用于表示类似表格的数据结构,包含行(row)、列(column)以及对应的单元格值(cell value)。行和列共同组成一个有序的键对(key pair),用于定位单元格中的值。
2. Guava 的 Table
简介
2.1. Maven 依赖
首先,在 pom.xml
中添加 Guava 的依赖:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.3-jre</version>
</dependency>
最新版本可以在 Maven Central 查看。
2.2. 原理说明
✅ 如果要用 Java 原生的集合来模拟 Guava 的 Table
,可以把它理解为一个嵌套的 Map:Map<RowKey, Map<ColumnKey, Value>>
。
Table
实际上是一种特殊的 Map,它允许通过两个键(行键和列键)的组合来定位一个值。举个例子,可以用来表示大学与课程、剩余席位之间的关系:Map<UniversityName, Map<CourseName, SeatCount>>
。
📌 实战场景中,Table
也非常适合用于像战舰游戏的棋盘这种二维数据结构。
3. 创建 Table
的几种方式
创建 Table
实例有以下几种常见方式:
使用
HashBasedTable.create()
,底层使用LinkedHashMap
:Table<String, String, Integer> universityCourseSeatTable = HashBasedTable.create();
如果需要对行键和列键进行排序,可以使用
TreeBasedTable.create()
,底层是TreeMap
:Table<String, String, Integer> universityCourseSeatTable = TreeBasedTable.create();
如果事先知道行和列的键,并且数据结构固定,可以使用
ArrayTable.create()
:List<String> universityRowTable = Lists.newArrayList("Mumbai", "Harvard"); List<String> courseColumnTables = Lists.newArrayList("Chemical", "IT", "Electrical"); Table<String, String, Integer> universityCourseSeatTable = ArrayTable.create(universityRowTable, courseColumnTables);
如果需要一个不可变的
Table
,可以使用ImmutableTable
,通过 Builder 模式构建:Table<String, String, Integer> universityCourseSeatTable = ImmutableTable.<String, String, Integer>builder() .put("Mumbai", "Chemical", 120) .build();
4. 使用示例
4.1. 获取值
如果你知道行键和列键,可以直接通过 get(rowKey, columnKey)
获取值:
@Test
public void givenTable_whenGet_returnsSuccessfully() {
Table<String, String, Integer> universityCourseSeatTable = HashBasedTable.create();
universityCourseSeatTable.put("Mumbai", "Chemical", 120);
universityCourseSeatTable.put("Mumbai", "IT", 60);
universityCourseSeatTable.put("Harvard", "Electrical", 60);
universityCourseSeatTable.put("Harvard", "IT", 120);
int seatCount = universityCourseSeatTable.get("Mumbai", "IT");
Integer seatCountForNoEntry = universityCourseSeatTable.get("Oxford", "IT");
assertThat(seatCount).isEqualTo(60);
assertThat(seatCountForNoEntry).isEqualTo(null);
}
4.2. 判断是否存在
可以通过以下方式判断 Table
中是否存在某个条目:
- 判断某行某列是否存在:
contains(rowKey, columnKey)
- 判断某列是否存在:
containsColumn(columnKey)
- 判断某行是否存在:
containsRow(rowKey)
- 判断某个值是否存在:
containsValue(value)
@Test
public void givenTable_whenContains_returnsSuccessfully() {
Table<String, String, Integer> universityCourseSeatTable = HashBasedTable.create();
universityCourseSeatTable.put("Mumbai", "Chemical", 120);
universityCourseSeatTable.put("Mumbai", "IT", 60);
universityCourseSeatTable.put("Harvard", "Electrical", 60);
universityCourseSeatTable.put("Harvard", "IT", 120);
boolean entryIsPresent = universityCourseSeatTable.contains("Mumbai", "IT");
boolean courseIsPresent = universityCourseSeatTable.containsColumn("IT");
boolean universityIsPresent = universityCourseSeatTable.containsRow("Mumbai");
boolean seatCountIsPresent = universityCourseSeatTable.containsValue(60);
assertThat(entryIsPresent).isTrue();
assertThat(courseIsPresent).isTrue();
assertThat(universityIsPresent).isTrue();
assertThat(seatCountIsPresent).isTrue();
}
4.3. 删除条目
通过 remove(rowKey, columnKey)
删除指定条目:
@Test
public void givenTable_whenRemove_returnsSuccessfully() {
Table<String, String, Integer> universityCourseSeatTable = HashBasedTable.create();
universityCourseSeatTable.put("Mumbai", "Chemical", 120);
universityCourseSeatTable.put("Mumbai", "IT", 60);
int seatCount = universityCourseSeatTable.remove("Mumbai", "IT");
assertThat(seatCount).isEqualTo(60);
assertThat(universityCourseSeatTable.remove("Mumbai", "IT")).isNull();
}
4.4. 获取某一列的映射
使用 column(columnKey)
可以获取某列的行键到值的映射:
@Test
public void givenTable_whenColumn_returnsSuccessfully() {
Table<String, String, Integer> universityCourseSeatTable = HashBasedTable.create();
universityCourseSeatTable.put("Mumbai", "Chemical", 120);
universityCourseSeatTable.put("Mumbai", "IT", 60);
universityCourseSeatTable.put("Harvard", "Electrical", 60);
universityCourseSeatTable.put("Harvard", "IT", 120);
Map<String, Integer> universitySeatMap = universityCourseSeatTable.column("IT");
assertThat(universitySeatMap).hasSize(2);
assertThat(universitySeatMap.get("Mumbai")).isEqualTo(60);
assertThat(universitySeatMap.get("Harvard")).isEqualTo(120);
}
4.5. 获取列的完整 Map 结构
使用 columnMap()
获取 Map<ColumnKey, Map<RowKey, Value>>
:
@Test
public void givenTable_whenColumnMap_returnsSuccessfully() {
Table<String, String, Integer> universityCourseSeatTable = HashBasedTable.create();
universityCourseSeatTable.put("Mumbai", "Chemical", 120);
universityCourseSeatTable.put("Mumbai", "IT", 60);
universityCourseSeatTable.put("Harvard", "Electrical", 60);
universityCourseSeatTable.put("Harvard", "IT", 120);
Map<String, Map<String, Integer>> courseKeyUniversitySeatMap = universityCourseSeatTable.columnMap();
assertThat(courseKeyUniversitySeatMap).hasSize(3);
assertThat(courseKeyUniversitySeatMap.get("IT")).hasSize(2);
assertThat(courseKeyUniversitySeatMap.get("Electrical")).hasSize(1);
assertThat(courseKeyUniversitySeatMap.get("Chemical")).hasSize(1);
}
4.6. 获取某一行的映射
使用 row(rowKey)
获取某行的列键到值的映射:
@Test
public void givenTable_whenRow_returnsSuccessfully() {
Table<String, String, Integer> universityCourseSeatTable = HashBasedTable.create();
universityCourseSeatTable.put("Mumbai", "Chemical", 120);
universityCourseSeatTable.put("Mumbai", "IT", 60);
universityCourseSeatTable.put("Harvard", "Electrical", 60);
universityCourseSeatTable.put("Harvard", "IT", 120);
Map<String, Integer> courseSeatMap = universityCourseSeatTable.row("Mumbai");
assertThat(courseSeatMap).hasSize(2);
assertThat(courseSeatMap.get("IT")).isEqualTo(60);
assertThat(courseSeatMap.get("Chemical")).isEqualTo(120);
}
4.7. 获取所有行键
使用 rowKeySet()
获取所有的行键:
@Test
public void givenTable_whenRowKeySet_returnsSuccessfully() {
Table<String, String, Integer> universityCourseSeatTable = HashBasedTable.create();
universityCourseSeatTable.put("Mumbai", "Chemical", 120);
universityCourseSeatTable.put("Mumbai", "IT", 60);
universityCourseSeatTable.put("Harvard", "Electrical", 60);
universityCourseSeatTable.put("Harvard", "IT", 120);
Set<String> universitySet = universityCourseSeatTable.rowKeySet();
assertThat(universitySet).hasSize(2);
}
4.8. 获取所有列键
使用 columnKeySet()
获取所有的列键:
@Test
public void givenTable_whenColKeySet_returnsSuccessfully() {
Table<String, String, Integer> universityCourseSeatTable = HashBasedTable.create();
universityCourseSeatTable.put("Mumbai", "Chemical", 120);
universityCourseSeatTable.put("Mumbai", "IT", 60);
universityCourseSeatTable.put("Harvard", "Electrical", 60);
universityCourseSeatTable.put("Harvard", "IT", 120);
Set<String> courseSet = universityCourseSeatTable.columnKeySet();
assertThat(courseSet).hasSize(3);
}
5. 总结
本文介绍了 Guava 库中 Table
接口的常用方法和实现方式。它提供了一种非常直观的方式来处理二维数据结构,特别适用于需要通过行键和列键共同定位值的场景。
📌 示例代码可以在 GitHub 项目 中找到,项目基于 Maven 构建,导入即可运行。