Java中没有Pair<L,R>,有什么好理由吗?与这个c++构造等价的是什么?我宁愿避免重新实现我自己的。
似乎1.6提供了类似的东西(AbstractMap.SimpleEntry<K,V>),但这看起来相当复杂。
Java中没有Pair<L,R>,有什么好理由吗?与这个c++构造等价的是什么?我宁愿避免重新实现我自己的。
似乎1.6提供了类似的东西(AbstractMap.SimpleEntry<K,V>),但这看起来相当复杂。
当前回答
android提供了Pairclass (http://developer.android.com/reference/android/util/Pair.html),这里实现:
public class Pair<F, S> {
public final F first;
public final S second;
public Pair(F first, S second) {
this.first = first;
this.second = second;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Pair)) {
return false;
}
Pair<?, ?> p = (Pair<?, ?>) o;
return Objects.equal(p.first, first) && Objects.equal(p.second, second);
}
@Override
public int hashCode() {
return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
}
public static <A, B> Pair <A, B> create(A a, B b) {
return new Pair<A, B>(a, b);
}
}
其他回答
@Andreas Krey的回答其实很好。任何Java给你带来困难的事情,你都不应该去做。
在我的经验中,Pair最常见的用途是一个方法的多个返回值和hashmap中的values(通常由字符串索引)。
在后一种情况下,我最近使用了一个数据结构,类似这样:
class SumHolder{MyObject trackedObject, double sum};
这是您的整个“Pair”类,与通用的“Pair”类的代码数量几乎相同,但具有描述性名称的优势。它可以在它使用的方法中定义,这将消除公共变量等典型问题。换句话说,对于这种用法,它绝对比一对更好(由于命名的成员),不会更差。
If you actually want a "Pair" for the key of a hashmap you are essentially creating a double-key index. I think this may be the one case where a "Pair" is significantly less code. It's not really easier because you could have eclipse generate equals/hash on your little data class, but it would be a good deal more code. Here a Pair would be a quick fix, but if you need a double-indexed hash who's to say you don't need an n-indexed hash? The data class solution will scale up, the Pair will not unless you nest them!
So the second case, returning from a method, is a bit harder. Your class needs more visibility (the caller needs to see it too). You can define it outside the method but inside the class exactly as above. At that point your method should be able to return a MyClass.SumHolder object. The caller gets to see the names of the returned objects, not just a "Pair". Note again that the "Default" security of package level is pretty good--it's restrictive enough that you shouldn't get yourself into too much trouble. Better than a "Pair" object anyway.
我能看到的另一种情况是使用一个公共api,为当前包之外的调用者提供返回值。为此,我只创建一个真正的对象——最好是不可变的。最终,调用者将共享此返回值,并且使其可变可能会出现问题。这是Pair对象更糟糕的另一种情况——大多数Pair不能被设置为不可变的。
所有这些情况的另一个优点是——java类扩展,我的sum类需要第二个sum和“Created”标记,当我完成时,我将不得不扔掉Pair并使用其他东西,但如果Pair有意义,我的4个值的类至少仍然有意义。
虽然这个问题已经有十多年的历史了,但我觉得有必要提一下,从Java 14开始,Records可以为这个问题提供非常简单和轻量级的解决方案,而不需要任何形式的外部库或依赖项。
例如,以下记录类声明将是实现所需功能所需的全部内容:
record Pair<K, V>(K key, V value) { }
这样一个记录类可以这样使用:
// Declare a pair object containing two integers
var integerIntegerPair = new Pair<>(1, 2);
// Declare a pair object containing a String and an integer
var stringIntegerPair = new Pair<>("String", 20);
// Declare a pair object containing two other pairs!
var pairPairPair = new Pair<>(new Pair<>(1, 2), new Pair<>("String", 20));
正如许多人已经指出的那样,Pair类是否有用实际上取决于用例。
我认为,对于私有帮助函数,如果使用Pair类可以使代码更具可读性,并且不值得花费精力创建另一个包含所有锅炉代码的值类,那么使用Pair类是完全合法的。
另一方面,如果您的抽象级别要求您清楚地记录包含两个对象或值的类的语义,那么您应该为它编写一个类。如果数据是业务对象,通常就是这种情况。
一如既往,这需要熟练的判断。
对于你的第二个问题,我推荐Apache Commons库中的Pair类。这些可能被认为是Java的扩展标准库:
https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/Pair.html
你可能还想看看Apache Commons的EqualsBuilder、HashCodeBuilder和ToStringBuilder,它们简化了为业务对象编写值类的过程。
在我看来,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++的人可能不会理解。另一种方法是在类型层次结构中编写很多类,在类型参数上有不同的边界,但是有太多可能的边界和它们的组合……
简单的方法Object[] -可以作为一个几何体元组使用