Java中的C ++ Pair <L,R>等效项是什么?

时间:2020-03-06 14:57:40  来源:igfitidea点击:

有充分的理由为什么Java中没有Pair &lt;L,R>?这个C ++构造相当于什么?我宁愿避免重新实现自己的。

似乎1.6提供了类似的东西(AbstractMap.SimpleEntry &lt;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 &lt;,那么pair :: operator &lt;也不会编译。

无边界可比的示例:

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"和静态构造函数。