在Java开发中,我们经常面临一个方法需要返回多个关联值的场景:比如接口返回结果数据+状态码+提示信息,或者查询返回主键+名称+时间戳。传统方案要么创建冗余的自定义封装类,要么使用类型不安全的Map,前者增加代码维护成本,后者容易出现类型转换错误和键名混乱。而Apache Commons Lang3库中的PairTriple工具类,恰好解决了这些痛点,让多值返回更简洁、类型更安全。

一、快速上手:依赖引入

使用PairTriple前,需先引入Apache Commons Lang3依赖,支持Maven和Gradle两种构建方式:

Maven依赖

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.14.0</version> <!-- 推荐使用最新稳定版 -->
</dependency>

Gradle依赖

implementation 'org.apache.commons:commons-lang3:3.14.0'

二、Pair:轻量键值对容器

Pair是用于存储两个关联值的抽象类,核心优势是实现了Map.EntryComparable接口,支持集合操作和对象比较,同时保持类型安全。它提供两个核心子类,适配不同可变需求。

核心特性

  • 支持泛型定义左右值类型,避免类型转换
  • 实现序列化接口,可用于网络传输和持久化
  • 提供静态工厂方法of(),简化对象创建
  • 成员变量leftright可直接访问,也支持getLeft()/getRight()方法

1. MutablePair:可变键值对

适用于需要动态修改值的场景,非线程安全,支持通过setLeft()setRight()方法更新值。

实战示例:订单状态更新
import org.apache.commons.lang3.tuple.MutablePair;

// 模拟订单实体
class OrderDO {
    private String orderId;
    private Integer status; // 0-待支付,1-已支付,2-已取消

    // getter/setter省略
}

public class MutablePairDemo {
    // 处理订单状态,返回订单ID和更新后的状态
    private static MutablePair<String, Integer> updateOrderStatus(OrderDO order) {
        MutablePair<String, Integer> pair = MutablePair.of(order.getOrderId(), order.getStatus());
        if (order.getStatus() == 0) {
            pair.setRight(1); // 更新状态为已支付
        }
        return pair;
    }

    public static void main(String[] args) {
        OrderDO order = new OrderDO();
        order.setOrderId("ORD2025001");
        order.setStatus(0);

        MutablePair<String, Integer> result = updateOrderStatus(order);
        System.out.printf("订单ID:%s,更新后状态:%s%n", 
            result.getLeft(), result.getRight() == 1 ? "已支付" : "待支付");
    }
}

2. ImmutablePair:不可变键值对

创建后无法修改左右值,线程安全,适合多线程环境或值无需变更的场景。其leftright成员变量被声明为final,调用setValue()会抛出UnsupportedOperationException

实战示例:用户信息查询
import org.apache.commons.lang3.tuple.ImmutablePair;

public class ImmutablePairDemo {
    // 查询用户姓名和年龄,返回不可变键值对
    private static ImmutablePair<String, Integer> queryUserInfo(String userId) {
        // 模拟数据库查询
        String userName = "张三";
        Integer age = 28;
        return ImmutablePair.of(userName, age);
    }

    public static void main(String[] args) {
        ImmutablePair<String, Integer> userPair = queryUserInfo("U2025001");
        System.out.printf("用户名:%s,年龄:%d%n", userPair.getLeft(), userPair.getRight());

        // 尝试修改会抛出异常
        try {
            userPair.setValue(30);
        } catch (UnsupportedOperationException e) {
            System.out.println("不可变Pair不支持修改操作");
        }
    }
}

三、Triple:三元组全能工具

当需要返回三个关联值时,Triple成为最优解。它在Pair的基础上增加了中间值(Middle),同样提供可变和不可变两个子类,完美适配复杂多值场景。

核心特性

  • 支持左值(Left)、中间值(Middle)、右值(Right)三层数据
  • 保持与Pair一致的API设计,降低学习成本
  • 支持null值存储,灵活应对部分字段为空的场景

1. MutableTriple:可变三元组

允许通过setLeft()setMiddle()setRight()方法动态更新三个值,非线程安全,适用于需要中途修改数据的业务场景。

实战示例:商品库存操作
import org.apache.commons.lang3.tuple.MutableTriple;

class ProductDO {
    private String productId;
    private String productName;
    private Integer stock; // 库存数量

    // getter/setter省略
}

public class MutableTripleDemo {
    // 扣减库存,返回商品ID、商品名称、扣减后库存
    private static MutableTriple<String, String, Integer> deductStock(ProductDO product, int num) {
        MutableTriple<String, String, Integer> triple = MutableTriple.of(
            product.getProductId(), product.getProductName(), product.getStock()
        );
        if (product.getStock() >= num) {
            triple.setRight(product.getStock() - num); // 更新库存
        }
        return triple;
    }

    public static void main(String[] args) {
        ProductDO product = new ProductDO();
        product.setProductId("PROD2025001");
        product.setProductName("Java编程指南");
        product.setStock(100);

        MutableTriple<String, String, Integer> result = deductStock(product, 20);
        System.out.printf("商品ID:%s,商品名称:%s,剩余库存:%d%n",
            result.getLeft(), result.getMiddle(), result.getRight());
    }
}

2. ImmutableTriple:不可变三元组

创建后三个值均不可修改,线程安全。若存储的对象本身是可变类型(如自定义类),需注意对象内部状态可能被修改的风险。

实战示例:接口响应封装
import org.apache.commons.lang3.tuple.ImmutableTriple;

public class ImmutableTripleDemo {
    // 模拟接口响应:状态码(int)、提示信息(String)、响应数据(Object)
    private static ImmutableTriple<Integer, String, Object> buildResponse(boolean success) {
        if (success) {
            return ImmutableTriple.of(200, "操作成功", "{\"data\":\"success\"}");
        } else {
            return ImmutableTriple.of(500, "服务器内部错误", null);
        }
    }

    public static void main(String[] args) {
        ImmutableTriple<Integer, String, Object> successResp = buildResponse(true);
        System.out.printf("状态码:%d,提示:%s,数据:%s%n",
            successResp.getLeft(), successResp.getMiddle(), successResp.getRight());

        ImmutableTriple<Integer, String, Object> failResp = buildResponse(false);
        System.out.printf("状态码:%d,提示:%s,数据:%s%n",
            failResp.getLeft(), failResp.getMiddle(), failResp.getRight());
    }
}

四、多值返回方案对比

为了帮助你选择最合适的方案,这里对比Pair/Triple与传统方案的核心差异:

方案 优点 缺点 适用场景
Pair/Triple 无需自定义类、类型安全、API简洁 仅支持2-3个值、语义不如自定义类清晰 简单多值返回、临时数据传递
自定义封装类 语义清晰、可扩展、支持多字段 代码冗余、需维护getter/setter 复杂业务对象、长期复用的数据结构
Map<String, Object> 无需预定义结构、灵活 类型不安全、键名易出错、可读性差 临时存储非固定结构数据
Java 16+ Record 简洁无冗余、语义清晰 需JDK16+、不可变(部分场景不适用) JDK16+环境、不可变数据封装

五、实战注意事项

  1. 线程安全选择:多线程环境优先使用ImmutablePairImmutableTriple;单线程或无需修改值的场景,也建议优先使用不可变版本,避免意外修改。
  2. 不可变性陷阱ImmutableTriple存储可变对象(如自定义类)时,对象内部状态可被修改,需谨慎处理。
  3. 字段语义:由于Pair/Triple仅通过left/middle/right标识字段,复杂场景下建议搭配注释说明各字段含义,或改用自定义类。
  4. 版本兼容:确保commons-lang3版本≥3.12.0,避免旧版本存在的API差异问题。

六、总结

PairTriple作为Java多值返回的轻量解决方案,完美平衡了简洁性和实用性。它们无需创建冗余的自定义类,保持了类型安全,同时提供灵活的可变/不可变选择,大幅提升开发效率。在简单多值返回场景(如接口响应、临时数据传递、查询结果封装)中,是替代自定义类和Map的最优选择。

合理运用这两个工具类,能让你的代码更简洁、更易维护,同时避免传统方案的诸多痛点。建议在项目中引入Apache Commons Lang3库,充分发挥这些工具类的价值。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐