⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 网络 「网络」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

在日常的 Java 编码实践里,我们常常会碰到一个方法需要返回多个值的情况。比如,在处理某个操作时,我们不仅要返回操作的结果,还得带上一些与之相关的附加信息。传统的做法是创建一个自定义类来封装这些信息,或者使用集合(像 Map)来存储这些值。然而,这样做往往会让代码变得臃肿复杂,调用方在理解和提取这些值时也会感到颇为棘手。

这时,org.apache.commons.lang3.tuple 包下的 Pair 和 Triple 及其子类就成了绝佳的解决方案。它们为我们提供了一种清晰、简洁的方式来组织和传递多个相关联的值,让代码变得更加直观易懂。

引入依赖

在使用 Pair 和 Triple 之前,我们需要在项目中引入 Apache Commons Lang3 库的依赖。在 Maven 项目里,只需在 pom.xml 文件中添加以下依赖即可:

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>

Pair 类:便捷的键值对容器

Pair 类概述

Pair 类是 Apache Commons Lang3 库提供的一个抽象类,用于表示简单的键值对。它实现了 Map.Entry 接口,这意味着它可以在各种集合中使用;同时,它还实现了 Comparable 接口,方便我们比较两个 Pair 对象的大小;并且支持对象的序列化和反序列化。

下面是 Pair 类的部分源码:

/**
* 抽象类,表示简单的键值对。
* 实现了 Map.Entry 接口,支持在各种集合中使用。
* 实现了 Comparable 接口,用于比较两个 Pair 对象的大小。
* 可序列化,支持对象的序列化和反序列化。
*
* @param <L> 左值的类型
* @param <R> 右值的类型
*/
publicabstractclass Pair<L, R> implements Map.Entry<L, R>, Comparable<Pair<L, R>>, Serializable {

privatestaticfinallong serialVersionUID = 4954918890077093841L;

// 空数组,用于表示空的 Pair 对象数组
publicstaticfinal Pair<?, ?>[] EMPTY_ARRAY = new PairAdapter[0];

/**
* 返回一个空的 Pair 数组。
*
* @return 空的 Pair 数组
*/
publicstatic <L, R> Pair<L, R>[] emptyArray() {
return (Pair[]) EMPTY_ARRAY;
}

/**
* 静态工厂方法,创建一个新的 ImmutablePair 对象,表示给定的左右值的键值对。
*
* @param left 左值
* @param right 右值
* @param <L> 左值的类型
* @param <R> 右值的类型
* @return ImmutablePair 对象
*/
publicstatic <L, R> Pair<L, R> of(L left, R right) {
return ImmutablePair.of(left, right);
}

/**
* 静态工厂方法,创建一个新的 ImmutablePair 对象,表示给定 Map.Entry 对象的键值对。
*
* @param pair Map.Entry 对象
* @param <L> 左值的类型
* @param <R> 右值的类型
* @return ImmutablePair 对象
*/
publicstatic <L, R> Pair<L, R> of(Map.Entry<L, R> pair) {
return ImmutablePair.of(pair);
}

/**
* 返回左值,实现了 Map.Entry 接口。
*
* @return 左值
*/
public final L getKey() {
returnthis.getLeft();
}

/**
* 抽象方法,由子类实现,用于获取左值。
*
* @return 左值
*/
public abstract L getLeft();

/**
* 抽象方法,由子类实现,用于获取右值。
*
* @return 右值
*/
public abstract R getRight();

/**
* 返回右值,实现了 Map.Entry 接口。
*
* @return 右值
*/
public R getValue() {
returnthis.getRight();
}
}

Pair 类有两个重要的子类:ImmutablePair 和 MutablePair,下面我们来详细了解一下这两个子类。

MutablePair:可变的键值对

MutablePair 是一个可变的键值对类,它允许我们在创建后动态修改键和值,这为我们的编程带来了更大的灵活性。不过需要注意的是,它是非线程安全的,在多线程环境下使用时需要格外小心。

我们可以通过以下几种方式来构造 MutablePair 对象:

同时,MutablePair 还提供了一些方法来修改和获取键值:

需要注意的是,MutablePair 的 left 和 right 成员变量是 public 的,我们也可以直接访问它们来获取值。

ImmutablePair:不可变的键值对

ImmutablePair 是 Pair 的一个不可变子类,一旦创建完成,其键和值就不能再被改变,这使得它是线程安全的,适合在多线程环境下使用。

下面是 ImmutablePair 的构造方式:

ImmutablePair 提供了获取键值的方法:

// 获取左值
public L getLeft();

// Pair 中的方法,获取左值
public final L getKey();

// 获取右值
public R getRight();

// Pair 中的方法,获取右值
public R getValue();

同样,ImmutablePair 的 left 和 right 成员变量是 public 的,我们可以直接访问它们。

为什么 ImmutablePair 是不可变的且线程安全呢?原因在于它的左值和右值成员变量被声明为 final,一旦初始化就不能再被修改。并且,调用它的 setValue 方法会抛出 UnsupportedOperationException 异常。

public final L left;  
public final R right;

public R setValue(R value) {
throw new UnsupportedOperationException();
}

Pair 使用示例

class UserDO {
private String userId;
private Integer age;

public String getUserId() {
return userId;
}

public void setUserId(String userId) {
this.userId = userId;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}
}

在上述示例中,我们可以看到 ImmutablePair 在尝试修改值时会抛出异常,这体现了它的不可变性。

Triple 类:强大的三元组工具

Triple 类概述

Triple 是一个用于表示三元组的抽象类。三元组是由三个元素组成的有序集合,分别称为左值(Left)、中间值(Middle)和右值(Right)。Triple 类为我们提供了一种便捷的方式来组织和处理这种具有固定顺序的数据,让我们可以在不创建专门类的情况下轻松返回三个值,减少了创建和维护多个变量的复杂性,使代码更加简洁。

下面是 Triple 类的部分源码:

/**
* 表示包含三个元素的三元组的抽象类 Triple。
*
* 该类是一个抽象实现,定义了基本的 API,将元素分别称为 'left'、'middle' 和 'right'。
*
* 子类的实现可以是可变的或不可变的。对存储的对象类型没有限制。
* Triple 对象的可变性取决于其中存储的对象是否是可变的。如果存储的是可变对象,那么 Triple 本身也就变得可变,因为存储的对象状态可以被修改。
* 如果存储的是不可变对象,那么 Triple 对象在创建后就保持不可变。
*
*/
publicabstractclass Triple<L, M, R> implements Comparable<Triple<L, M, R>>, Serializable {

/**
* 一个空数组。
*/
publicstaticfinal Triple<?, ?, ?>[] EMPTY_ARRAY = new TripleAdapter[0];

/**
* 返回可分配而无需编译器警告的空数组单例。
*
*/
@SuppressWarnings("unchecked")
publicstatic <L, M, R> Triple<L, M, R>[] emptyArray() {
return (Triple<L, M, R>[]) EMPTY_ARRAY;
}

/**
* 获取由三个对象组成的不可变三元组,推断出泛型类型。
*
* 此工厂方法允许使用推断类型来创建三元组以获取泛型类型。
*
* @param left 左元素,可以为 null
* @param middle 中间元素,可以为 null
* @param right 右元素,可以为 null
* @return 由三个参数形成的三元组,非 null
*/
publicstatic <L, M, R> Triple<L, M, R> of(final L left, final M middle, final R right) {
returnnew ImmutableTriple<>(left, middle, right);
}

/**
* 获取此三元组的左元素。
*
* @return 左元素,可以为 null
*/
public abstract L getLeft();

/**
* 获取此三元组的中间元素。
*
* @return 中间元素,可以为 null
*/
public abstract M getMiddle();

/**
* 获取此三元组的右元素。
*
* @return 右元素,可以为 null
*/
public abstract R getRight();
}

Triple 类有两个子类:可变的 MutableTriple 和不可变的 ImmutableTriple。

MutableTriple:可变的三元组

MutableTriple 是可变的三元组类,它提供了公共的设置(set)方法,允许我们在创建后修改其内部值。具体来说,MutableTriple 提供了 setLeft、setMiddle 和 setRight 方法,使得我们可以在对象创建后修改左、中、右元素的值。需要注意的是,MutableTriple 是非线程安全的。

下面是 MutableTriple 的部分源码:

/**
* 表示由三个 {@code Object} 元素组成的可变三元组。
*
* 非线程安全
*
*/
publicclass MutableTriple<L, M, R> extends Triple<L, M, R> {


/**
* 通过推断泛型类型获取三个对象的可变三元组。
*
* 该工厂允许通过推断泛型类型创建三元组。
*
*/
publicstatic <L, M, R> MutableTriple<L, M, R> of(final L left, final M middle, final R right) {
returnnew MutableTriple<>(left, middle, right);
}

/** 左对象 */
public L left;
/** 中间对象 */
public M middle;
/** 右对象 */
public R right;

/**
* 创建一个新的三元组实例,包含三个 null 值。
*/
public MutableTriple() {
}

/**
* 创建一个新的三元组实例。
*
* @param left 左值,可以为 null
* @param middle 中间值,可以为 null
* @param right 右值,可以为 null
*/
public MutableTriple(final L left, final M middle, final R right) {
this.left = left;
this.middle = middle;
this.right = right;
}

/**
* 设置三元组的左元素。
*/
public void setLeft(final L left) {
this.left = left;
}

/**
* 设置三元组的中间元素。
*/
public void setMiddle(final M middle) {
this.middle = middle;
}

/**
* 设置三元组的右元素。
*/
public void setRight(final R right) {
this.right = right;
}
}

ImmutableTriple:不可变的三元组

ImmutableTriple 是一个不可变的三元组类,由三个泛型元素(left、middle、right)组成。一旦创建,其状态就无法修改,因此它是线程安全的。不过需要注意的是,如果存储在三元组中的对象是可变的,那么三元组本身实际上就不再是不可变的。

下面是 ImmutableTriple 的部分源码:

/**
* 一个由三个元素组成的不可变三元组。
*
* ImmutableTriple 是一个最终类,被设计成不可变的,即在实例化后其状态不可更改。
* 如果存储在三元组中的三个对象都是线程安全的,则该类是线程安全的。类的最终性防止了子类化,确保不会添加不希望的行为。
*
* 线程安全的 如果三个对象都是线程安全的
*
*/
publicfinalclass ImmutableTriple<L, M, R> extends Triple<L, M, R> {

/**
* 返回可以在不触发编译器警告的情况下分配的空数组单例。
* @return 可以在不触发编译器警告的情况下分配的空数组单例。
*/
@SuppressWarnings("unchecked")
publicstatic <L, M, R> ImmutableTriple<L, M, R>[] emptyArray() {
return (ImmutableTriple<L, M, R>[]) EMPTY_ARRAY;
}

/**
* 返回一个由 null 组成的不可变三元组。
*
* @return 一个由 null 组成的不可变三元组。
*/
publicstatic <L, M, R> ImmutableTriple<L, M, R> nullTriple() {
return NULL;
}

/**
* 通过推断泛型类型获得由三个对象组成的不可变三元组。
*
* 此工厂允许使用推断创建三元组以获得泛型类型。
*
* @return 由三个参数形成的不可变三元组,不为 null
*/
publicstatic <L, M, R> ImmutableTriple<L, M, R> of(final L left, final M middle, final R right) {
returnnew ImmutableTriple<>(left, middle, right);
}

/** 左对象 */
publicfinal L left;
/** 中间对象 */
publicfinal M middle;
/** 右对象 */
publicfinal R right;

/**
* 构造方法 创建一个新的三元组实例。
*
*/
public ImmutableTriple(final L left, final M middle, final R right) {
this.left = left;
this.middle = middle;
this.right = right;
}
}

Triple 使用示例

class UserDO {
private String userId;
private String userName;
private Integer sex;

public String getUserId() {
return userId;
}

public void setUserId(String userId) {
this.userId = userId;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public Integer getSex() {
return sex;
}

public void setSex(Integer sex) {
this.sex = sex;
}
}

总结

通过使用 Pair 和 Triple 类,我们可以显著简化代码,提高代码的可读性。它们让关联数据更加清晰明了,同时保持了类型安全,增强了代码的清晰度和扩展性。

此外,这些类还提供了丰富的功能,使开发人员能够更高效地处理相关数据,编写出更简洁、易读的代码,从而提升代码质量和开发效率。希望大家在今后的 Java 开发中能够充分利用这些实用的工具类。

文章目录
  1. 1. 引入依赖
  2. 2. Pair 类:便捷的键值对容器
    1. 2.1. Pair 类概述
    2. 2.2. MutablePair:可变的键值对
    3. 2.3. ImmutablePair:不可变的键值对
    4. 2.4. Pair 使用示例
  3. 3. Triple 类:强大的三元组工具
    1. 3.1. Triple 类概述
    2. 3.2. MutableTriple:可变的三元组
    3. 3.3. ImmutableTriple:不可变的三元组
    4. 3.4. Triple 使用示例
  4. 4. 总结