提出问题
很多时候,方法需要返回 2个值 或 多个值
比如返回 姓名、年龄、性别,除了使用 数组 Array、集合(List、Set、Map)这些容器类型之外,在Java中我们就必须创建一个Class来作为返回类型。
但很多时候只需要 2 至 5 个值,这个时候非要定义一个class就很烦琐了
解决
此时可以使用 元组 Tuple
元祖 Tuple
和列表List一样,都用于数据存储,包含 多个数据
但是和列表 不同的是:列表只能存储 相同 的数据类型(不用泛型就存成 Object )
而元组可以存储 不同的数据类型,比如同时存储 int、string、list
很多语言都提供 元组 Tuple ,比如 .NET Framework 最多支持7个元素的元组;Scala最多支持22个元素的元组;C++(STL)的Tuple;
JDK原生不支持元祖,但 github的 javatuples支持元祖:
https://github.com/javatuples/javatuples
限制
数量限制
元祖一般有最大值,不能无限添加,个人认为,数量 2 - 3 个 最为合理,超过 4个,不易理解,还是建议用封装类
比如:用在方法返回值,可以返回 2 -3 个值,容易说明和理解
不能修改
从 数据结构 来讲,元祖中的元素 不能修改
代码实现
下面是从 hbase 中反编译的 Tuple 源码,略有改动
Tuple2
可以存2个元素
import java.io.Serializable;
public class Tuple2<T1, T2> implements Serializable {
private static final long serialVersionUID = -3986244606585552569L;
protected T1 first = null;
protected T2 second = null;
/**
* Default constructor.
*/
public Tuple2() {
}
/**
* Constructor
*
* @param a operand
* @param b operand
*/
public Tuple2(T1 a, T2 b) {
this.first = a;
this.second = b;
}
/**
* Constructs a new pair, inferring the type via the passed arguments
*
* @param <T1> type for first
* @param <T2> type for second
* @param a first element
* @param b second element
* @return a new pair containing the passed arguments
*/
public static <T1, T2> Tuple2<T1, T2> create(T1 a, T2 b) {
return new Tuple2<>(a, b);
}
/**
* Replace the first element of the pair.
*
* @param a operand
*/
public void setFirst(T1 a) {
this.first = a;
}
/**
* Replace the second element of the pair.
*
* @param b operand
*/
public void setSecond(T2 b) {
this.second = b;
}
/**
* Return the first element stored in the pair.
*
* @return T1
*/
public T1 getFirst() {
return first;
}
/**
* Return the second element stored in the pair.
*
* @return T2
*/
public T2 getSecond() {
return second;
}
private static boolean equals(Object x, Object y) {
return (x == null && y == null) || (x != null && x.equals(y));
}
@Override
@SuppressWarnings("unchecked")
public boolean equals(Object other) {
return other instanceof Tuple2 && equals(first, ((Tuple2) other).first) &&
equals(second, ((Tuple2) other).second);
}
@Override
public int hashCode() {
if (first == null)
return (second == null) ? 0 : second.hashCode() + 1;
else if (second == null)
return first.hashCode() + 2;
else
return first.hashCode() * 17 + second.hashCode();
}
@Override
public String toString() {
return "{" + getFirst() + "," + getSecond() + "}";
}
}
Tuple3
public class Tuple3<A, B, C> {
private A first;
private B second;
private C third;
// default constructor
public Tuple3() {
}
public Tuple3(A first, B second, C third) {
this.first = first;
this.second = second;
this.third = third;
}
// ctor cannot infer types w/o warning but a method can.
public static <A, B, C> Tuple3<A, B, C> create(A first, B second, C third) {
return new Tuple3<>(first, second, third);
}
@Override
public int hashCode() {
int hashFirst = (first != null ? first.hashCode() : 0);
int hashSecond = (second != null ? second.hashCode() : 0);
int hashThird = (third != null ? third.hashCode() : 0);
return (hashFirst >> 1) ^ hashSecond ^ (hashThird << 1);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Tuple3)) {
return false;
}
Tuple3<?, ?, ?> otherTriple = (Tuple3<?, ?, ?>) obj;
if (first != otherTriple.first && (first != null && !(first.equals(otherTriple.first))))
return false;
if (second != otherTriple.second && (second != null && !(second.equals(otherTriple.second))))
return false;
if (third != otherTriple.third && (third != null && !(third.equals(otherTriple.third))))
return false;
return true;
}
@Override
public String toString() {
return "(" + first + ", " + second + "," + third + " )";
}
public A getFirst() {
return first;
}
public void setFirst(A first) {
this.first = first;
}
public B getSecond() {
return second;
}
public void setSecond(B second) {
this.second = second;
}
public C getThird() {
return third;
}
public void setThird(C third) {
this.third = third;
}
}