Java中没有Pair<L,R>,有什么好理由吗?与这个c++构造等价的是什么?我宁愿避免重新实现我自己的。
似乎1.6提供了类似的东西(AbstractMap.SimpleEntry<K,V>),但这看起来相当复杂。
Java中没有Pair<L,R>,有什么好理由吗?与这个c++构造等价的是什么?我宁愿避免重新实现我自己的。
似乎1.6提供了类似的东西(AbstractMap.SimpleEntry<K,V>),但这看起来相当复杂。
当前回答
在我看来,Java中没有Pair,因为如果你想直接在Pair上添加额外的功能(例如Comparable),你必须绑定类型。在c++中,我们不在乎,如果组成一个pair的类型没有操作符<,则pair::operator <也不会被编译。
Comparable的一个例子:
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));
Comparable与编译时检查类型参数是否可比较的示例:
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中使用不可比较的类型作为类型参数。 你可能会在一些实用程序类中使用很多comparator for Pair,但是c++的人可能不会理解。另一种方法是在类型层次结构中编写很多类,在类型参数上有不同的边界,但是有太多可能的边界和它们的组合……
其他回答
实现Pair with的另一种方法。
Public immutable fields, i.e. simple data structure. Comparable. Simple hash and equals. Simple factory so you don't have to provide the types. e.g. 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 + ')'; } }
在我看来,Java中没有Pair,因为如果你想直接在Pair上添加额外的功能(例如Comparable),你必须绑定类型。在c++中,我们不在乎,如果组成一个pair的类型没有操作符<,则pair::operator <也不会被编译。
Comparable的一个例子:
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));
Comparable与编译时检查类型参数是否可比较的示例:
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中使用不可比较的类型作为类型参数。 你可能会在一些实用程序类中使用很多comparator for Pair,但是c++的人可能不会理解。另一种方法是在类型层次结构中编写很多类,在类型参数上有不同的边界,但是有太多可能的边界和它们的组合……
为了方便起见,以下是一些具有多级元组的库:
JavaTuples。它只有1-10度的元组。 JavaSlang。0-8度的元组和许多其他功能性的东西。 jOOλ。0-16度的元组和其他一些功能性的好东西。(免责声明,我在维修公司工作) Functional Java。0-8度的元组和许多其他功能性的东西。
已经提到的其他库至少包含Pair元组。
具体来说,在函数式编程的上下文中,它使用了大量的结构类型,而不是名义类型(正如公认答案中提倡的那样),这些库及其元组非常方便。
这是Java。您必须使用描述性的类名和字段名创建自己定制的Pair类,不要介意通过编写hashCode()/equals()或一次又一次地实现Comparable来重新发明轮子。
根据Java语言的性质,我认为人们实际上并不需要Pair,通常他们需要的是一个接口。这里有一个例子:
interface Pair<L, R> {
public L getL();
public R getR();
}
所以,当人们想要返回两个值时,他们可以这样做:
... //Calcuate the return value
final Integer v1 = result1;
final String v2 = result2;
return new Pair<Integer, String>(){
Integer getL(){ return v1; }
String getR(){ return v2; }
}
This is a pretty lightweight solution, and it answers the question "What is the semantic of a Pair<L,R>?". The answer is, this is an interface build with two (may be different) types, and it has methods to return each of them. It is up to you to add further semantic to it. For example, if you are using Position and REALLY want to indicate it in you code, you can define PositionX and PositionY that contains Integer, to make up a Pair<PositionX,PositionY>. If JSR 308 is available, you may also use Pair<@PositionX Integer, @PositionY Ingeger> to simplify that.
编辑: 这里我应该指出的一点是,上面的定义显式地将类型参数名和方法名联系起来。这是对那些认为Pair缺乏语义信息的人的回答。实际上,getL方法的意思是“给我对应于类型参数L的类型的元素”,这确实意味着什么。
编辑: 下面是一个简单的实用程序类,可以让生活变得更简单:
class Pairs {
static <L,R> Pair<L,R> makePair(final L l, final R r){
return new Pair<L,R>(){
public L getL() { return l; }
public R getR() { return r; }
};
}
}
用法:
return Pairs.makePair(new Integer(100), "123");