Java中的C ++ Pair <L,R>等效项是什么?
有充分的理由为什么Java中没有Pair <L,R>?这个C ++构造相当于什么?我宁愿避免重新实现自己的。
似乎1.6提供了类似的东西(AbstractMap.SimpleEntry <K,V>),但这看起来有些令人费解。
解决方案
这取决于我们要使用它的目的。这样做的典型原因是遍历地图,我们只需为此进行操作(Java 5+):
Map<String, Object> map = ... ; // just an example
for (Map.Entry<String, Object> entry : map.entrySet()) {
System.out.printf("%s -> %s\n", entry.getKey(), entry.getValue());
}
在comp.lang.java.help上的一个线程中,Hunter Gratzner提出了一些反对Java中是否存在Pair构造的参数。主要论点是,类" Pair"不会传达有关两个值之间关系的任何语义(我们如何知道"第一"和"第二"的含义?)。
更好的做法是为每个将要由Pair类组成的应用程序编写一个非常简单的类,如Mike提出的那样。 " Map.Entry"是一对名称中带有其含义的对的示例。
综上所述,我认为最好有一个类Position(x,y),一个类Range(begin,end)和一个类Entry(key,value)而不是一般的对。 (第一,第二)`并没有告诉我应该做什么。
HashMap兼容的Pair类:
public class Pair<A, B> {
private A first;
private B second;
public Pair(A first, B second) {
super();
this.first = first;
this.second = second;
}
public int hashCode() {
int hashFirst = first != null ? first.hashCode() : 0;
int hashSecond = second != null ? second.hashCode() : 0;
return (hashFirst + hashSecond) * hashSecond + hashFirst;
}
public boolean equals(Object other) {
if (other instanceof Pair) {
Pair otherPair = (Pair) other;
return
(( this.first == otherPair.first ||
( this.first != null && otherPair.first != null &&
this.first.equals(otherPair.first))) &&
( this.second == otherPair.second ||
( this.second != null && otherPair.second != null &&
this.second.equals(otherPair.second))) );
}
return false;
}
public String toString()
{
return "(" + first + ", " + second + ")";
}
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;
}
}
Pair是一个好东西,成为复杂泛型的基本构造单元,例如,这是从我的代码中得出的:
WeakHashMap<Pair<String, String>, String> map = ...
与Haskell的元组相同
这是Java。我们必须使用描述性的类和字段名称来制作自己的量身定制的Pair类,并且不要介意通过编写hashCode()/ equals()或者一次又一次地实现Comparable来重新发明轮子。
实现配对的另一种方法。
- 公共不可变字段,即简单的数据结构。
- 可比。
- 简单的哈希和等于。
- 简单的工厂,因此我们不必提供类型。例如Pair.of(" hello",1);
public class Pair<FIRST, SECOND> implements Comparable<Pair<FIRST, SECOND>> {
public final FIRST first;
public final SECOND second;
private Pair(FIRST first, SECOND second) {
this.first = first;
this.second = second;
}
public static <FIRST, SECOND> Pair<FIRST, SECOND> of(FIRST first,
SECOND second) {
return new Pair<FIRST, SECOND>(first, second);
}
@Override
public int compareTo(Pair<FIRST, SECOND> o) {
int cmp = compare(first, o.first);
return cmp == 0 ? compare(second, o.second) : cmp;
}
// todo move this to a helper class.
private static int compare(Object o1, Object o2) {
return o1 == null ? o2 == null ? 0 : -1 : o2 == null ? +1
: ((Comparable) o1).compareTo(o2);
}
@Override
public int hashCode() {
return 31 * hashcode(first) + hashcode(second);
}
// todo move this to a helper class.
private static int hashcode(Object o) {
return o == null ? 0 : o.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Pair))
return false;
if (this == obj)
return true;
return equal(first, ((Pair) obj).first)
&& equal(second, ((Pair) obj).second);
}
// todo move this to a helper class.
private boolean equal(Object o1, Object o2) {
return o1 == null ? o2 == null : (o1 == o2 || o1.equals(o2));
}
@Override
public String toString() {
return "(" + first + ", " + second + ')';
}
}
Object []可以用作三维元组的简单方法
我认为Java中没有对,因为如果我们想直接在对上添加额外的功能(例如Comparable),则必须对类型进行绑定。在C ++中,我们不在乎,如果组成一个对的类型不具有operator <,那么pair :: operator <也不会编译。
无边界可比的示例:
public class Pair<F, S> implements Comparable<Pair<? extends F, ? extends S>> {
public final F first;
public final S second;
/* ... */
public int compareTo(Pair<? extends F, ? extends S> that) {
int cf = compare(first, that.first);
return cf == 0 ? compare(second, that.second) : cf;
}
//Why null is decided to be less than everything?
private static int compare(Object l, Object r) {
if (l == null) {
return r == null ? 0 : -1;
} else {
return r == null ? 1 : ((Comparable) (l)).compareTo(r);
}
}
}
/* ... */
Pair<Thread, HashMap<String, Integer>> a = /* ... */;
Pair<Thread, HashMap<String, Integer>> b = /* ... */;
//Runtime error here instead of compile error!
System.out.println(a.compareTo(b));
比较类型与编译时检查类型参数是否可比的示例:
public class Pair<
F extends Comparable<? super F>,
S extends Comparable<? super S>
> implements Comparable<Pair<? extends F, ? extends S>> {
public final F first;
public final S second;
/* ... */
public int compareTo(Pair<? extends F, ? extends S> that) {
int cf = compare(first, that.first);
return cf == 0 ? compare(second, that.second) : cf;
}
//Why null is decided to be less than everything?
private static <
T extends Comparable<? super T>
> int compare(T l, T r) {
if (l == null) {
return r == null ? 0 : -1;
} else {
return r == null ? 1 : l.compareTo(r);
}
}
}
/* ... */
//Will not compile because Thread is not Comparable<? super Thread>
Pair<Thread, HashMap<String, Integer>> a = /* ... */;
Pair<Thread, HashMap<String, Integer>> b = /* ... */;
System.out.println(a.compareTo(b));
很好,但是这一次我们不能在Pair中将不可比较的类型用作类型参数。
在某些实用工具类中,可能会为Pair使用很多Comparators,但C ++人士可能无法使用它。另一种方法是在类型层次结构中编写许多类,对类型实参使用不同的界限,但是可能的界限及其组合太多了...
使用Lombok,我能想到的最短的一对是:
@Data
@AllArgsConstructor(staticName = "of")
public class Pair<F, S> {
private F first;
private S second;
}
它具有@arturh的答案的所有优点(可比性除外),具有" hashCode"," equals"," toString"和静态构造函数。

