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