有没有一个很好的理由为什么Pair
Java中没有?这个C++构造的等价物是什么?我宁愿避免重新实现自己.
似乎1.6提供类似的东西(AbstractMap.SimpleEntry
),但这看起来很复杂.
在一个线程中comp.lang.java.help
,Hunter Gratzner提出了一些反对Pair
Java中构造的存在的论据.主要论点是一个类Pair
没有传达关于两个值之间关系的任何语义(你怎么知道"第一"和"第二"是什么意思?).
更好的做法是为每个应用程序编写一个非常简单的类,就像Mike提出的Pair
类一样.Map.Entry
是一个在其名称中带有其含义的对的示例.
总而言之,在我看来,最好有一个类Position(x,y)
,一个类Range(begin,end)
和一个类,Entry(key,value)
而不是一个通用的Pair(first,second)
,它不会告诉我它应该做什么.
这是Java.您必须使用描述性类和字段名称来创建自己的定制Pair类,并且不要介意通过编写hashCode()/ equals()或一次又一次地实现Comparable来重新发明轮子.
HashMap兼容Pair类:
public class Pair { 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; } }
使用Lombok,我能想到的最短的一对是:
@Data @AllArgsConstructor(staticName = "of") public class Pair{ private F first; private S second; }
它具有的所有优点的答案从@arturh(可比性除外),它有hashCode
,equals
,toString
和静态的"构造".
Apache Commons Lang 3.0+有几个Pair类:http: //commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/package-summary.html
另一种实现Pair的方法.
公共不可变字段,即简单的数据结构.
可比.
简单的哈希和等于.
简单的工厂,所以你不必提供类型.例如Pair.of("你好",1);
public class Pairimplements Comparable > { public final FIRST first; public final SECOND second; private Pair(FIRST first, SECOND second) { this.first = first; this.second = second; } public static Pair of(FIRST first, SECOND second) { return new Pair (first, second); } @Override public int compareTo(Pair 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 + ')'; } }
http://www.javatuples.org/index.html怎么样我发现它非常有用.
javatuples为您提供从1到10个元素的元组类:
Unit (1 element) Pair (2 elements) Triplet (3 elements) Quartet (4 elements) Quintet (5 elements) Sextet (6 elements) Septet (7 elements) Octet (8 elements) Ennead (9 elements) Decade (10 elements)
这取决于你想用它做什么.这样做的典型原因是迭代地图,您只需执行此操作(Java 5+):
Mapmap = ... ; // just an example for (Map.Entry entry : map.entrySet()) { System.out.printf("%s -> %s\n", entry.getKey(), entry.getValue()); }
android提供了Pair
类(http://developer.android.com/reference/android/util/Pair.html),这里的实现:
public class Pair{ 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 Pair create(A a, B b) { return new Pair(a, b); } }
最大的问题可能是无法确保A和B的不变性(请参阅如何确保类型参数是不可变的)因此hashCode()
可能会在插入集合之后为同一对提供不一致的结果(这会产生未定义的行为) ,请参阅根据可变字段定义等于).对于特定(非泛型)Pair类,程序员可以通过仔细选择A和B为不可变来确保不变性.
无论如何,从@ PeterLawrey的答案中清除泛型的警告(java 1.7):
public class Pair, B extends Comparable super B>> implements Comparable> { public final A first; public final B second; private Pair(A first, B second) { this.first = first; this.second = second; } public static , B extends Comparable super B>> Pair of(A first, B second) { return new Pair(first, second); } @Override public int compareTo(Pair o) { int cmp = o == null ? 1 : (this.first).compareTo(o.first); return cmp == 0 ? (this.second).compareTo(o.second) : cmp; } @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 == o2 || (o1 != null && o1.equals(o2)); } @Override public String toString() { return "(" + first + ", " + second + ')'; } }
非常欢迎添加/更正:)特别是我对我的使用不太确定Pair, ?>
.
有关此语法原因的详细信息,请参阅确保对象实现Comparable以及详细说明如何max(Comparable a, Comparable b)
在Java中实现泛型函数?
好消息JavaFX
具有关键价值。
只需将javafx添加为依赖项并导入javafx.util.Pair
;
并像中那样简单地使用c++
。
Pair
例如
Pairpr = new Pair () pr.get(key);// will return corresponding value
在我看来,Java中没有Pair,因为如果你想直接在对上添加额外的功能(例如Comparable),你必须绑定类型.在C++中,我们只是不关心,如果组成一对的类型没有operator <
,那么pair::operator <
也不会编译.
没有边界的可比较的示例:
public class Pairimplements Comparable > { 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 > a = /* ... */; Pair > 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> { 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 > a = /* ... */; Pair > b = /* ... */; System.out.println(a.compareTo(b));
这很好,但是这次你可能不会在Pair中使用非可比类型作为类型参数.在某些实用程序类中,可能会使用大量的Comparators for Pair,但C++人员可能无法获得它.另一种方法是在类型层次结构中编写许多类,在类型参数上使用不同的边界,但是有太多可能的边界及其组合......
正如许多其他人已经说过的那样,如果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,它们简化了为业务对象编写值类的过程.
JavaFX(与Java 8捆绑在一起)具有Pair 类
您可以使用javafx实用程序类,Pair
其作用与c ++中的pair <>相同。https://docs.oracle.com/javafx/2/api/javafx/util/Pair.html