关于元组:Java中C ++ Pair 的等价物是什么?

What is the equivalent of the C++ Pair in Java?

有没有一个很好的理由为什么Java中没有Pair? 这个C ++构造的等价物是什么? 我宁愿避免重新实现自己。

似乎1.6提供了类似的东西(AbstractMap.SimpleEntry),但这看起来很复杂。


comp.lang.java.help上的一个线程中,Hunter Gratzner给出了一些反对在Java中存在Pair结构的论据。主要论点是类Pair没有传达关于两个值之间关系的任何语义(你怎么知道"第一"和"第二"是什么意思?)。

更好的做法是为每个应用程序编写一个非常简单的类,就像Mike提出的那样,对于Pair类。 Map.Entry是在其名称中带有其含义的一对的示例。

总而言之,在我看来,最好有一个类Position(x,y),一个类Range(begin,end)和一个类Entry(key,value)而不是一个通用的Pair(first,second),它不会告诉我它应该做什么。


这是Java。您必须使用描述性类和字段名称来创建自己的定制Pair类,并且不要介意通过编写hashCode()/ equals()或一次又一次地实现Comparable来重新发明轮子。


HashMap兼容Pair类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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;
    }
}

使用Lombok,我能想到的最短的一对是:

1
2
3
4
5
6
@Data
@AllArgsConstructor(staticName ="of")
public class Pair<F, S> {
    private F first;
    private S second;
}

它具有@arturh答案的所有好处(可比性除外),它具有hashCodeequalstoString和静态"构造函数"。


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);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    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 + ')';
        }
    }

http://www.javatuples.org/index.html怎么样我发现它非常有用。

javatuples为您提供从1到10个元素的元组类:

1
2
3
4
5
6
7
8
9
10
Unit<A> (1 element)
Pair<A,B> (2 elements)
Triplet<A,B,C> (3 elements)
Quartet<A,B,C,D> (4 elements)
Quintet<A,B,C,D,E> (5 elements)
Sextet<A,B,C,D,E,F> (6 elements)
Septet<A,B,C,D,E,F,G> (7 elements)
Octet<A,B,C,D,E,F,G,H> (8 elements)
Ennead<A,B,C,D,E,F,G,H,I> (9 elements)
Decade<A,B,C,D,E,F,G,H,I,J> (10 elements)

android提供Pair类(http://developer.android.com/reference/android/util/Pair.html),这里实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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);
    }
}

这取决于你想用它做什么。这样做的典型原因是迭代地图,您只需执行此操作(Java 5+):

1
2
3
4
5
Map<String, Object> map = ... ; // just an example
for (Map.Entry<String, Object> entry : map.entrySet()) {
  System.out.printf("%s -> %s
"
, entry.getKey(), entry.getValue());
}


最大的问题可能是无法确保A和B的不变性(请参阅如何确保类型参数是不可变的)因此hashCode()可能会在插入集合之后为同一对提供不一致的结果(这样会给出未定义的行为,请参阅根据可变字段定义等于)。对于特定(非泛型)Pair类,程序员可以通过仔细选择A和B为不可变来确保不变性。

无论如何,从@ PeterLawrey的答案中清除泛型的警告(java 1.7):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class Pair<A extends Comparable<? super A>,
                    B extends Comparable<? super B>>
        implements Comparable<Pair<A, B>> {

    public final A first;
    public final B second;

    private Pair(A first, B second) {
        this.first = first;
        this.second = second;
    }

    public static <A extends Comparable<? super A>,
                    B extends Comparable<? super B>>
            Pair<A, B> of(A first, B second) {
        return new Pair<A, B>(first, second);
    }

    @Override
    public int compareTo(Pair<A, B> 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以及详细说明如何在Java中实现泛型max(Comparable a, Comparable b)函数?


正如许多其他人已经说过的那样,如果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,因为如果你想在对上添加额外的功能(例如Comparable),你必须绑定类型。在C ++中,我们只是不关心,如果组成一对的类型没有operator <pair::operator <也不会编译。

没有边界的可比较的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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与编译时检查的示例是否类型参数具有可比性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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中使用非可比类型作为类型参数。
在某些实用程序类中,可能会使用大量的Comparators for Pair,但C ++人员可能无法获得它。另一种方法是在类型层次结构中编写许多类,在类型参数上使用不同的边界,但是有太多可能的边界及其组合......


JavaFX(与Java 8捆绑在一起)具有Pair


好消息Java增加了键值对。

只需导入javafx.util.Pair;

并在c++中使用。

1
Pair < Key , Value >

例如

1
2
3
Pair < Integer , Integer > pr = new Pair<Integer , Integer>()

pr.get(key); // will return corresponding value


您可以使用javafx实用程序类Pair,它与c ++中的pair <>具有相同的用途。 https://docs.oracle.com/javafx/2/api/javafx/util/Pair.html


1
Collections.singletonMap(left, rigth);

Map.Entry接口非常接近c ++对。查看具体实现,如AbstractMap.SimpleEntry和AbstractMap.SimpleImmutableEntry
第一项是getKey(),第二项是getValue()。


尽管语法上相似,但Java和C ++有着截然不同的范例。编写像Java这样的C ++是糟糕的C ++,编写像C ++这样的Java是糟糕的Java。

使用像Eclipse这样的基于反射的IDE,编写"对"类的必要功能非常简单快捷。创建类,定义两个字段,使用各种"Generate XX"菜单选项在几秒钟内填写该类。如果你想要Comparable接口,也许你必须快速输入"compareTo"。

使用C ++语言中的单独声明/定义选项代码生成器并不是那么好,因此手工编写小实用程序类会耗费时间。因为该对是模板,所以您不必为不使用的函数付费,并且typedef工具允许为代码分配有意义的类型名称,因此关于"无语义"的异议并没有真正支持。


根据Java语言的本质,我认为人们实际上并不需要Pair,接口通常是他们所需要的。这是一个例子:

1
2
3
4
interface Pair<L, R> {
    public L getL();
    public R getR();
}

因此,当人们想要返回两个值时,他们可以执行以下操作:

1
2
3
4
5
6
7
... //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; }
}

这是一个非常轻量级的解决方案,它回答了"Pair的语义是什么?"的问题。答案是,这是一个具有两个(可能是不同的)类型的接口构建,并且它具有返回每个类型的方法。您可以在其中添加更多语义。例如,如果您正在使用Position并且确实想在代码中指明它,则可以定义包含IntegerPositionXPositionY,以构成Pair。如果JSR 308可用,您也可以使用Pair<@PositionX Integer, @PositionY Ingeger>来简化它。

编辑:
我应该在这里指出的一件事是上面的定义明确地涉及类型参数名称和方法名称。这是对那些认为Pair缺乏语义信息的答案。实际上,方法getL的意思是"给我一个与类型参数L的类型相对应的元素",这意味着什么。

编辑:
这是一个简单的实用程序类,可以使生活更轻松:

1
2
3
4
5
6
7
8
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; }  
        };
    }
}

用法:

1
return Pairs.makePair(new Integer(100),"123");


您可以使用Google的AutoValue库 - https://github.com/google/auto/tree/master/value。

您创建了一个非常小的抽象类,并使用@AutoValue对其进行注释,并且注释处理器为您生成具有值语义的具体类。


Brian Goetz,Paul Sandoz和Stuart Marks解释了为什么在Devoxx'14的QA会议期间。

一旦引入了价值类型,在标准库中具有通用对类将变成技术债务。

另请参阅:Java SE 8是否具有Pairs或Tuples?


对于像Java这样的编程语言,大多数程序员用来表示像数据结构这样的对的备用数据结构是两个数组,并且通过相同的索引访问数据

例如:http://www-igm.univ-mlv.fr/~lecroq/string/node8.html#SECTION0080

这并不理想,因为数据应绑定在一起,但结果也相当便宜。此外,如果您的用例需要存储坐标,那么最好建立自己的数据结构。

我的图书馆里有这样的东西

1
public class Pair<First,Second>{.. }

配对将是一个很好的东西,成为复杂泛型的基本构造单元,例如,这来自我的代码:

1
WeakHashMap<Pair<String, String>, String> map = ...

它和Haskell的Tuple一样


以下是一些具有多个元组度的库,以方便您:

  • JavaTuples。 1-10级的元组就是它的全部。
  • JavaSlang。 0-8级的元组和许多其他功能性好东西。
  • jOOλ。 0-16级的元组和其他一些功能性好东西。 (免责声明,我为维护公司工作)
  • 功能Java。 0-8级的元组和许多其他功能性好东西。

已经提到其他库至少包含Pair元组。

具体来说,在函数式编程的上下文中,它使用了大量的结构类型,而不是名义上的类型(如接受的答案所提倡的),这些库和它们的元组非常方便。


com.sun.tools.javac.util.Pair是一对的简单实现。
它可以在jdk1.7.0_51 lib tools.jar中找到。

除了org.apache.commons.lang3.tuple.Pair之外,它不仅仅是一个界面。


我注意到所有的Pair实现都在这里散布,属性意味着两个值的顺序。当我想到一对时,我想到了两个项目的组合,其中两个项目的顺序并不重要。这是我对无序对的实现,其中hashCodeequals覆盖以确保集合中的所需行为。也可克隆。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/**
 * The class <wyn>Pair</wyn> models a container for two objects wherein the
 * object order is of no consequence for equality and hashing. An example of
 * using Pair would be as the return type for a method that needs to return two
 * related objects. Another good use is as entries in a Set or keys in a Map
 * when only the unordered combination of two objects is of interest.<p>

 * The term"object" as being a one of a Pair can be loosely interpreted. A
 * Pair may have one or two <wyn>null</wyn> entries as values. Both values
 * may also be the same object.<p>

 * Mind that the order of the type parameters T and U is of no importance. A
 * Pair&lt;T, U> can still return <wyn>true</wyn> for method <wyn>equals</wyn>
 * called with a Pair&lt;U, T> argument.<p>

 * Instances of this class are immutable, but the provided values might not be.
 * This means the consistency of equality checks and the hash code is only as
 * strong as that of the value types.<p>

 */

public class Pair<T, U> implements Cloneable {

    /**
     * One of the two values, for the declared type T.
     */

    private final T object1;
    /**
     * One of the two values, for the declared type U.
     */

    private final U object2;
    private final boolean object1Null;
    private final boolean object2Null;
    private final boolean dualNull;

    /**
     * Constructs a new <wyn>Pair&lt;T, U&gt;</wyn> with T object1 and U object2 as
     * its values. The order of the arguments is of no consequence. One or both of
     * the values may be <wyn>null</wyn> and both values may be the same object.
     *
     * @param object1 T to serve as one value.
     * @param object2 U to serve as the other value.
     */

    public Pair(T object1, U object2) {

        this.object1 = object1;
        this.object2 = object2;
        object1Null = object1 == null;
        object2Null = object2 == null;
        dualNull = object1Null && object2Null;

    }

    /**
     * Gets the value of this Pair provided as the first argument in the constructor.
     *
     * @return a value of this Pair.
     */

    public T getObject1() {

        return object1;

    }

    /**
     * Gets the value of this Pair provided as the second argument in the constructor.
     *
     * @return a value of this Pair.
     */

    public U getObject2() {

        return object2;

    }

    /**
     * Returns a shallow copy of this Pair. The returned Pair is a new instance
     * created with the same values as this Pair. The values themselves are not
     * cloned.
     *
     * @return a clone of this Pair.
     */

    @Override
    public Pair<T, U> clone() {

        return new Pair<T, U>(object1, object2);

    }

    /**
     * Indicates whether some other object is"equal" to this one.
     * This Pair is considered equal to the object if and only if
     *
<ul>

     *
<li>
the Object argument is not null,
     *
<li>
the Object argument has a runtime type Pair or a subclass,
     *
</ul>

     * AND
     *
<ul>

     *
<li>
the Object argument refers to this pair
     *
<li>
OR this pair's values are both null and the other pair's values are both null
     *
<li>
OR this pair has one null value and the other pair has one null value and
     * the remaining non-null values of both pairs are equal
     *
<li>
OR both pairs have no null values and have value tuples &lt;v1, v2> of
     * this pair and &lt;o1, o2> of the other pair so that at least one of the
     * following statements is true:
     *
<ul>

     *
<li>
v1 equals o1 and v2 equals o2
     *
<li>
v1 equals o2 and v2 equals o1
     *
</ul>

     *
</ul>

     * In any other case (such as when this pair has two null parts but the other
     * only one) this method returns false.<p>

     * The type parameters that were used for the other pair are of no importance.
     * A Pair&lt;T, U> can return <wyn>true</wyn> for equality testing with
     * a Pair&lt;T, V> even if V is neither a super- nor subtype of U, should
     * the the value equality checks be positive or the U and V type values
     * are both <wyn>null</wyn>. Type erasure for parameter types at compile
     * time means that type checks are delegated to calls of the <wyn>equals</wyn>
     * methods on the values themselves.
     *
     * @param obj the reference object with which to compare.
     * @return true if the object is a Pair equal to this one.
     */

    @Override
    public boolean equals(Object obj) {

        if(obj == null)
            return false;

        if(this == obj)
            return true;

        if(!(obj instanceof Pair<?, ?>))
            return false;

        final Pair<?, ?> otherPair = (Pair<?, ?>)obj;

        if(dualNull)
            return otherPair.dualNull;

        //After this we're sure at least one part in this is not null

        if(otherPair.dualNull)
            return false;

        //After this we're sure at least one part in obj is not null

        if(object1Null) {
            if(otherPair.object1Null) //Yes: this and other both have non-null part2
                return object2.equals(otherPair.object2);
            else if(otherPair.object2Null) //Yes: this has non-null part2, other has non-null part1
                return object2.equals(otherPair.object1);
            else //Remaining case: other has no non-null parts
                return false;
        } else if(object2Null) {
            if(otherPair.object2Null) //Yes: this and other both have non-null part1
                return object1.equals(otherPair.object1);
            else if(otherPair.object1Null) //Yes: this has non-null part1, other has non-null part2
                return object1.equals(otherPair.object2);
            else //Remaining case: other has no non-null parts
                return false;
        } else {
            //Transitive and symmetric requirements of equals will make sure
            //checking the following cases are sufficient
            if(object1.equals(otherPair.object1))
                return object2.equals(otherPair.object2);
            else if(object1.equals(otherPair.object2))
                return object2.equals(otherPair.object1);
            else
                return false;
        }

    }

    /**
     * Returns a hash code value for the pair. This is calculated as the sum
     * of the hash codes for the two values, wherein a value that is <wyn>null</wyn>
     * contributes 0 to the sum. This implementation adheres to the contract for
     * <wyn>hashCode()</wyn> as specified for <wyn>Object()</wyn>. The returned
     * value hash code consistently remain the same for multiple invocations
     * during an execution of a Java application, unless at least one of the pair
     * values has its hash code changed. That would imply information used for
     * equals in the changed value(s) has also changed, which would carry that
     * change onto this class' <wyn>equals</wyn> implementation.
     *
     * @return a hash code for this Pair.
     */

    @Override
    public int hashCode() {

        int hashCode = object1Null ? 0 : object1.hashCode();
        hashCode += (object2Null ? 0 : object2.hashCode());
        return hashCode;

    }

}

此实现已经过适当的单元测试,并且已经尝试了在Set和Map中的使用。

请注意,我并未声称要在公共领域发布此内容。这是我刚刚编写的用于应用程序的代码,所以如果你打算使用它,请不要直接复制并搞砸注释和名称。抓住我的漂移?


如果有人想要一个简单易用且易于使用的版本,我可以访问https://github.com/lfac-pt/Java-Pair。此外,非常欢迎改进!


另一个简洁的lombok实现

1
2
3
4
5
6
7
import lombok.Value;

@Value(staticConstructor ="of")
public class Pair<F, S> {
    private final F first;
    private final S second;
}

简单的方法Object [] - 可以用作自己的维度元组


许多人发布了可用作Map中键的Pair代码...如果你想使用一对作为哈希键(一个常见的习语),请务必查看Guava的Table:http ://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table。对于图形边缘,它们给出以下示例用法:

1
2
3
4
5
6
7
Table<Vertex, Vertex, Double> weightedGraph = HashBasedTable.create();
weightedGraph.put(v1, v2, 4);
weightedGraph.put(v1, v3, 20);
weightedGraph.put(v2, v3, 5);

weightedGraph.row(v1); // returns a Map mapping v2 to 4, v3 to 20
weightedGraph.column(v3); // returns a Map mapping v1 to 20, v2 to 5

Table将两个键映射到单个值,并且仅为两种类型的键提供有效的查找。我已经开始在我的代码的许多部分使用这个数据结构而不是Map, V>。密集和稀疏用途都有数组,树和其他实现,可以选择指定自己的中间映射类。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Pair<K, V> {

    private final K element0;
    private final V element1;

    public static <K, V> Pair<K, V> createPair(K key, V value) {
        return new Pair<K, V>(key, value);
    }

    public Pair(K element0, V element1) {
        this.element0 = element0;
        this.element1 = element1;
    }

    public K getElement0() {
        return element0;
    }

    public V getElement1() {
        return element1;
    }

}

用法:

1
2
3
Pair<Integer, String> pair = Pair.createPair(1,"test");
pair.getElement0();
pair.getElement1();

永恒,只有一对!


使用新版本的Lombok,你可以编译那个可爱的类:

1
2
3
@Value(staticConstructor ="of") public class Pair <E> {
  E first, second;
}

并使用它:Pair pairOfValues = Pair.of(value1, value2);


@Andreas Krey的回答实际上很好。任何Java都很困难,你可能不应该这样做。

根据我的经验,Pair的最常见用途是来自方法的多个返回值以及散列映射中的VALUES(通常由字符串索引)。

在后一种情况下,我最近使用了一个数据结构,如下所示:

1
class SumHolder{MyObject trackedObject, double sum};

有你的整个"配对"类,与通用的"配对"几乎相同的代码量,但具有描述性名称的优点。它可以在其使用的方法中直接定义,这将消除公共变量等的典型问题。换句话说,对于这种用法(由于命名的成员),它绝对比一对更好,并且没有更糟。

如果你真的想要一个"配对"作为散列图的键,你实际上是在创建一个双键索引。我认为这可能是"配对"显着减少代码的一种情况。这并不是那么容易,因为你可以让eclipse在你的小数据类上生成equals / hash,但这将是一个很好的代码。这里的一对将是一个快速修复,但如果你需要一个双索引哈希谁说你不需要一个n索引哈希?数据类解决方案将扩展,除非你嵌套它们,否则它们不会!

因此从方法返回的第二种情况有点难度。您的课程需要更多的可见性(调用者也需要查看它)。您可以在方法之外定义它,但在类中完全如上所述。此时,您的方法应该能够返回MyClass.SumHolder对象。调用者可以看到返回对象的名称,而不仅仅是"对"。再次注意,包级别的"默认"安全性非常好 - 它足够严格,你不应该让自己陷入太多麻烦。无论如何,比"配对"对象更好。

另一种情况我可以看到Pairs的用途是一个公共api,其中包含当前包之外的调用者的返回值。为此,我只是创建一个真正的对象 - 最好是不可变的。最终调用者将共享此返回值并使其可变可能会有问题。这是Pair对象更糟糕的另一种情况 - 大多数对不能成为不可变的。

所有这些情况的另一个优点 - java类扩展,我的sum类需要一个第二个和我创建时的"Created"标志,我将不得不扔掉这个和其他东西,但如果这对有意义,我的班级有4个值仍然至少有意义。