1. 概述

元组(Tuple)是一种可以包含多个元素的集合,这些元素之间可能有关联也可能无关。简单来说,元组可以看作是匿名对象。

例如,["RAM", 16, "Astra"] 就是一个包含三个元素的元组。

本教程将快速介绍一个超轻量级库 javatuples,它让我们能轻松操作基于元组的数据结构。

2. 内置的 Javatuples 类

该库提供了 10 个核心类,基本覆盖了所有元组使用场景:

基础元组类

  • Unit<A>(单元素)
  • Pair<A,B>(双元素)
  • Triplet<A,B,C>(三元素)
  • Quartet<A,B,C,D>(四元素)
  • Quintet<A,B,C,D,E>(五元素)
  • Sextet<A,B,C,D,E,F>(六元素)
  • Septet<A,B,C,D,E,F,G>(七元素)
  • Octet<A,B,C,D,E,F,G,H>(八元素)
  • Ennead<A,B,C,D,E,F,G,H,I>(九元素)
  • Decade<A,B,C,D,E,F,G,H,I,J>(十元素)

⚠️ 特殊语义类

  • KeyValue<A,B>(键值对)
  • LabelValue<A,B>(标签值对)

根据官方文档:所有 javatuples 类都是类型安全且不可变的,并实现了 IterableSerializableComparable 接口。

3. 添加 Maven 依赖

pom.xml 中添加依赖:

<dependency>
    <groupId>org.javatuples</groupId>
    <artifactId>javatuples</artifactId>
    <version>1.2</version>
</dependency>

最新版本可查看 Maven 中央仓库

4. 创建元组

创建元组非常简单粗暴:

方式一:构造器

Pair<String, Integer> pair = new Pair<String, Integer>("A pair", 55);

方式二:静态工厂方法(推荐)

Triplet<String, Integer, Double> triplet = Triplet.with("hello", 23, 1.2);

从集合创建

List<String> listOfNames = Arrays.asList("john", "doe", "anne", "alex");
Quartet<String, String, String, String> quartet
  = Quartet.fromCollection(collectionOfNames);

⚠️ 踩坑提醒:集合元素数量必须与元组阶数匹配!比如上面的四元素列表无法创建 Quintet(需要5个元素)。

从数组创建

String[] names = new String[] {"john", "doe", "anne"};
Triplet<String, String, String> triplet2 = Triplet.fromArray(names);

指定起始索引创建低阶元组

Pair<String, String> pairFromList = Pair.fromIterable(listOfNames, 2); // 取索引2和3

5. 获取元组值

类型安全方式(推荐)

通过 getValueX() 方法(X 从0开始):

Quartet<String, Double, Integer, String> quartet 
  = Quartet.with("john", 72.5, 32, "1051 SW");

String name = quartet.getValue0(); // 无需类型转换
Integer age = quartet.getValue2();
 
assertThat(name).isEqualTo("john");
assertThat(age).isEqualTo(32);

非类型安全方式

String name = (String) quartet.getValue(0); // 需要强制类型转换
Integer age = (Integer) quartet.getValue(2);

特殊说明:KeyValueLabelValue 类有专属方法 getKey()/getValue()getLabel()/getValue()

6. 修改元组值

由于元组不可变,所有修改操作都会返回新实例:

Pair<String, Integer> john = Pair.with("john", 32);
Pair<String, Integer> alex = john.setAt0("alex"); // 返回新元组

assertThat(john.toString()).isNotEqualTo(alex.toString()); // 原实例不变

7. 添加和删除元素

添加单个元素(自动升阶)

Pair<String, Integer> pair1 = Pair.with("john", 32);
Triplet<String, Integer, String> triplet1 = pair1.add("1051 SW");

assertThat(triplet1.contains("john")); // contains() 方法很实用
assertThat(triplet1.contains(32));
assertThat(triplet1.contains("1051 SW"));

合并两个元组

Pair<String, Integer> pair1 = Pair.with("john", 32);
Pair<String, Integer> pair2 = Pair.with("alex", 45);
Quartet<String, Integer, String, Integer> quartet2 = pair1.add(pair2);

assertThat(quartet2.containsAll(pair1)); // containsAll() 检查包含关系
assertThat(quartet2.containsAll(pair2));

指定位置插入

Pair<String, Integer> pair1 = Pair.with("john", 32);
Triplet<String, String, Integer> triplet2 = pair1.addAt1("1051 SW");

assertThat(triplet2.indexOf("john")).isEqualTo(0);
assertThat(triplet2.indexOf("1051 SW")).isEqualTo(1);
assertThat(triplet2.indexOf(32)).isEqualTo(2);

批量添加元素

Pair<String, Integer> pair1 = Pair.with("john", 32);
Quartet<String, Integer, String, Integer> quartet1 = pair1.add("alex", 45);

assertThat(quartet1.containsAll("alex", "john", 32, 45));

删除元素(自动降阶)

Pair<String, Integer> pair1 = Pair.with("john", 32);
Unit<Integer> unit = pair1.removeFrom0(); // 删除第一个元素

assertThat(unit.contains(32));

8. 转换为 List/Array

转换为 List

Quartet<String, Double, Integer, String> quartet
  = Quartet.with("john", 72.5, 32, "1051 SW");
List<Object> list = quartet.toList(); // 固定返回 List<Object>

assertThat(list.size()).isEqualTo(4);

转换为数组

Object[] array = quartet.toArray(); // 固定返回 Object[]

assertThat(array.length).isEqualTo(4);

9. 总结

Javatuples 是个简单粗暴的解决方案:

  • ✅ 类型安全且不可变
  • ✅ 语义清晰(如 Pair.with()new Pair<>() 更优雅)
  • ✅ 支持与集合/数组互操作
  • ❌ 元素数量固定(无法动态扩容)

完整示例代码见 GitHub 仓库,包含更多实用场景。


原始标题:Introduction to Javatuples