704

Is there a good reason why there is no Pair<L,R> in Java? What would be the equivalent of this C++ construct? I would rather avoid reimplementing my own.

It seems that 1.6 is providing something similar (AbstractMap.SimpleEntry<K,V>), but this looks quite convoluted.

4

36 回答 36

418

In a thread on comp.lang.java.help, Hunter Gratzner gives some arguments against the presence of a Pair construct in Java. The main argument is that a class Pair doesn't convey any semantics about the relationship between the two values (how do you know what "first" and "second" mean ?).

A better practice is to write a very simple class, like the one Mike proposed, for each application you would have made of the Pair class. Map.Entry is an example of a pair that carry its meaning in its name.

To sum up, in my opinion it is better to have a class Position(x,y), a class Range(begin,end) and a class Entry(key,value) rather than a generic Pair(first,second) that doesn't tell me anything about what it's supposed to do.

于 2008-10-01T08:18:24.500 回答
162

This is Java. You have to make your own tailored Pair class with descriptive class and field names, and not to mind that you will reinvent the wheel by writing hashCode()/equals() or implementing Comparable again and again.

于 2010-02-27T10:41:54.187 回答
108

HashMap compatible Pair class:

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;
    }
}
于 2009-03-24T12:55:19.613 回答
58

The shortest pair that I could come up with is the following, using Lombok:

@Data
@AllArgsConstructor(staticName = "of")
public class Pair<F, S> {
    private F first;
    private S second;
}

It has all the benefits of the answer from @arturh (except the comparability), it has hashCode, equals, toString and a static “constructor”.

于 2010-12-17T14:39:54.383 回答
40

Apache Commons Lang 3.0+ has a few Pair classes: http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/package-summary.html

于 2012-03-13T00:21:35.360 回答
32

Another way to implement Pair with.

  • Public immutable fields, i.e. simple data structure.
  • Comparable.
  • Simple hash and equals.
  • Simple factory so you don't have to provide the types. e.g. 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 + ')';
        }
    }
    
于 2010-09-05T14:27:25.763 回答
28

How about http://www.javatuples.org/index.html I have found it very useful.

The javatuples offers you tuple classes from one to ten elements:

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)
于 2012-03-01T19:02:17.057 回答
13

android provides Pairclass (http://developer.android.com/reference/android/util/Pair.html) , here the implementation:

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);
    }
}
于 2014-05-05T08:45:32.807 回答
12

It depends on what you want to use it for. The typical reason to do so is to iterate over maps, for which you simply do this (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());
}
于 2008-10-01T04:53:59.560 回答
9

The biggest problem is probably that one can't ensure immutability on A and B (see How to ensure that type parameters are immutable) so hashCode() may give inconsistent results for the same Pair after is inserted in a collection for instance (this would give undefined behavior, see Defining equals in terms of mutable fields). For a particular (non generic) Pair class the programmer may ensure immutability by carefully choosing A and B to be immutable.

Anyway, clearing generic's warnings from @PeterLawrey's answer (java 1.7) :

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 + ')';
    }
}

Additions/corrections much welcome :) In particular I am not quite sure about my use of Pair<?, ?>.

For more info on why this syntax see Ensure that objects implement Comparable and for a detailed explanation How to implement a generic max(Comparable a, Comparable b) function in Java?

于 2012-12-01T15:37:50.217 回答
9

Good News JavaFX has a key value Pair.

Just add JavaFX as a dependency and import javafx.util.Pair, and use simply as in C++.

Pair <Key, Value> 

e.g.

Pair <Integer, Integer> pr = new Pair<Integer, Integer>()

pr.get(key);// will return corresponding value
于 2016-01-24T14:10:35.490 回答
6

In my opinion, there is no Pair in Java because, if you want to add extra functionality directly on the pair (e.g. Comparable), you must bound the types. In C++, we just don't care, and if types composing a pair do not have operator <, the pair::operator < will not compile as well.

An example of Comparable with no bounding:

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

An example of Comparable with compile-time check for whether type arguments are 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));

This is good, but this time you may not use non-comparable types as type arguments in Pair. One may use lots of Comparators for Pair in some utility class, but C++ people may not get it. Another way is to write lots of classes in a type hierarchy with different bounds on type arguments, but there are too many possible bounds and their combinations...

于 2010-12-15T18:40:08.620 回答
6

Map.Entry interface come pretty close to c++ pair. Look at the concrete implementation, like AbstractMap.SimpleEntry and AbstractMap.SimpleImmutableEntry First item is getKey() and second is getValue().

于 2015-05-15T17:36:23.113 回答
5

As many others have already stated, it really depends on the use case if a Pair class is useful or not.

I think for a private helper function it is totally legitimate to use a Pair class if that makes your code more readable and is not worth the effort of creating yet another value class with all its boiler plate code.

On the other hand, if your abstraction level requires you to clearly document the semantics of the class that contains two objects or values, then you should write a class for it. Usually that's the case if the data is a business object.

As always, it requires skilled judgement.

For your second question I recommend the Pair class from the Apache Commons libraries. Those might be considered as extended standard libraries for Java:

https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/Pair.html

You might also want to have a look at Apache Commons' EqualsBuilder, HashCodeBuilder and ToStringBuilder which simplify writing value classes for your business objects.

于 2011-03-30T16:53:34.827 回答
5

According to the nature of Java language, I suppose people do not actually require a Pair, an interface is usually what they need. Here is an example:

interface Pair<L, R> {
    public L getL();
    public R getR();
}

So, when people want to return two values they can do the following:

... //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; }
}

This is a pretty lightweight solution, and it answers the question "What is the semantic of a Pair<L,R>?". The answer is, this is an interface build with two (may be different) types, and it has methods to return each of them. It is up to you to add further semantic to it. For example, if you are using Position and REALLY want to indicate it in you code, you can define PositionX and PositionY that contains Integer, to make up a Pair<PositionX,PositionY>. If JSR 308 is available, you may also use Pair<@PositionX Integer, @PositionY Ingeger> to simplify that.

EDIT: One thing I should indicate here is that the above definition explicitly relates the type parameter name and the method name. This is an answer to those argues that a Pair is lack of semantic information. Actually, the method getL means "give me the element that correspond to the type of type parameter L", which do means something.

EDIT: Here is a simple utility class that can make life easier:

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

usage:

return Pairs.makePair(new Integer(100), "123");
于 2012-11-08T23:28:08.737 回答
5

JavaFX (which comes bundled with Java 8) has the Pair< A,B > class

于 2015-04-20T23:04:09.280 回答
5

You can use javafx utility class, Pair which serves the same purpose as pair <> in c++. https://docs.oracle.com/javafx/2/api/javafx/util/Pair.html

于 2016-04-08T07:13:31.583 回答
4
Collections.singletonMap(left, rigth);
于 2016-02-12T09:16:57.280 回答
4

another terse lombok implementation

import lombok.Value;

@Value(staticConstructor = "of")
public class Pair<F, S> {
    private final F first;
    private final S second;
}
于 2018-11-19T18:28:27.823 回答
3

Simple way Object [] - can be use as anу dimention tuple

于 2010-09-29T06:44:19.270 回答
3

Despite being syntactically similar, Java and C++ have very different paradigms. Writing C++ like Java is bad C++, and writing Java like C++ is bad Java.

With a reflection based IDE like Eclipse, writing the necessarily functionality of a "pair" class is quick and simple. Create class, define two fields, use the various "Generate XX" menu options to fill out the class in a matter of seconds. Maybe you'd have to type a "compareTo" real quick if you wanted the Comparable interface.

With separate declaration / definition options in the language C++ code generators aren't so good, so hand writing little utility classes is more time consuming tedium. Because the pair is a template, you don't have to pay for functions you don't use, and the typedef facility allows assigning meaningful typenames to the code, so the objections about "no semantics" don't really hold up.

于 2014-02-17T21:19:06.843 回答
2

Pair would be a good stuff, to be a basic construction unit for a complex generics, for instance, this is from my code:

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

It is just the same as Haskell's Tuple

于 2010-02-03T14:44:10.510 回答
2

For programming languages like Java, the alternate data structure used by most programmers to represent pair like data-structures are two array, and data is accessed via the same index

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

This isn't ideal as the data should be bound together, but also turn out to be pretty cheap. Also, if your use case demands storing co-ordinates then its better to build your own data structure.

I've something like this in my library

public class Pair<First,Second>{.. }
于 2013-03-18T02:40:25.577 回答
2

You can use Google's AutoValue library - https://github.com/google/auto/tree/master/value.

You create a very small abstract class and annotate it with @AutoValue and the annotation processor generates a concrete class for you that has a value semantic.

于 2014-10-06T16:42:04.047 回答
2

Here are some libraries that have multiple degrees of tuples for your convenience:

  • JavaTuples. Tuples from degree 1-10 is all it has.
  • JavaSlang. Tuples from degree 0-8 and lots of other functional goodies.
  • jOOλ. Tuples from degree 0-16 and some other functional goodies. (Disclaimer, I work for the maintainer company)
  • Functional Java. Tuples from degree 0-8 and lots of other functional goodies.

Other libraries have been mentioned to contain at least the Pair tuple.

Specifically, in the context of functional programming which makes use of a lot of structural typing, rather than nominal typing (as advocated in the accepted answer), those libraries and their tuples come in very handy.

于 2015-10-22T13:48:20.667 回答
2

Brian Goetz, Paul Sandoz and Stuart Marks explain why during QA session at Devoxx'14.

Having generic pair class in standard library will turn into technical debt once value types introduced.

See also: Does Java SE 8 have Pairs or Tuples?

于 2016-03-02T22:19:01.467 回答
1

I noticed all the Pair implementations being strewn around here attribute meaning to the order of the two values. When I think of a pair, I think of a combination of two items in which the order of the two is of no importance. Here's my implementation of an unordered pair, with hashCode and equals overrides to ensure the desired behaviour in collections. Also cloneable.

/**
 * The class <code>Pair</code> 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 <code>null</code> 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 <code>true</code> for method <code>equals</code>
 * 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 <code>Pair&lt;T, U&gt;</code> 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 <code>null</code> 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 <code>true</code> 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 <code>null</code>. Type erasure for parameter types at compile
     * time means that type checks are delegated to calls of the <code>equals</code>
     * 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 <code>null</code>
     * contributes 0 to the sum. This implementation adheres to the contract for
     * <code>hashCode()</code> as specified for <code>Object()</code>. 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' <code>equals</code> 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;

    }

}

This implementation has been properly unit tested and the use in a Set and Map has been tried out.

Notice I'm not claiming to release this in the public domain. This is code I've just written for use in an application, so if you're going to use it, please refrain from making a direct copy and mess about with the comments and names a bit. Catch my drift?

于 2011-04-20T17:53:55.943 回答
1

If anyone wants a dead-simple and easy to use version I made my available at https://github.com/lfac-pt/Java-Pair. Also, improvements are very much welcome!

于 2012-01-05T22:22:57.483 回答
1

com.sun.tools.javac.util.Pair is an simple implementation of a pair. It can be found in jdk1.7.0_51\lib\tools.jar.

Other than the org.apache.commons.lang3.tuple.Pair, it's not just an interface.

于 2014-05-05T08:46:49.263 回答
0
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;
    }

}

usage :

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

Immutable, only a pair !

于 2011-12-09T10:55:59.450 回答
0

Many people are posting Pair code that is usable as a key in a Map...If you're trying to use a pair as a hashing key (a common idiom), be sure to check out Guava's Table<R,C,V>: http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table. They give the following example usage, for graph edges:

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

A Table maps two keys to a single value, and provides efficient lookups for both types of keys alone as well. I've started using this data structure instead of a Map<Pair<K1,K2>, V> in many parts of my code. There are array, tree, and other implementations for both dense and sparse uses, with the option of specifying your own intermediate map classes.

于 2012-12-28T04:40:01.233 回答
0

With new version of Lombok you can compile that cute class:

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

and use it like: Pair<Value> pairOfValues = Pair.of(value1, value2);

于 2016-01-27T11:28:55.147 回答
0

The answer by @Andreas Krey is actually good. Anything Java makes difficult, you probably shouldn't be doing.

The most common uses of Pair's in my experience have been multiple return values from a method and as VALUES in a hashmap (often indexed by strings).

In the latter case, I recently used a data structure, something like this:

class SumHolder{MyObject trackedObject, double sum};

There is your entire "Pair" class, pretty much the same amount of code as a generic "Pair" but with the advantage of descriptive names. It can be defined in-line right in the method it's used which will eliminate typical problems with public variables and the like. In other words, it's absolutely better than a pair for this usage (due to the named members) and no worse.

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.

The other case I can see a use for Pairs is a public api with return values for callers outside your current package. For this I'd just create a true object--preferably immutable. Eventually a caller will share this return value and having it mutable could be problematic. This is another case of the Pair object being worse--most pairs cannot be made immutable.

Another advantage to all these cases--the java class expands, my sum class needed a second sum and a "Created" flag by the time I was done, I would have had to throw away the Pair and gone with something else, but if the pair made sense, my class with 4 values still makes at least as much sense.

于 2017-07-17T21:37:18.073 回答
0

Try VAVR Tuples.

Not only does vavr have a good set of tuple types, it has great support for functional programming, too.

于 2020-07-08T01:00:13.483 回答
0

Spring data has a Pair and can be used like below,

Pair<S, T> pair = Pair.of(S type data, T type data)
于 2021-02-27T05:59:44.610 回答
0

Although this question is over a decade old, I do feel the need to mention that, as of Java 14, Records can provide a very simple and light-weight solution to this problem without the need for any form of external library or dependencies.

For example, the following record class declaration would be all that's required in order to achieve the desired functionality:

record Pair<K, V>(K key, V value) { }

Such a record class could be used as so:

// 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));
于 2021-09-16T18:11:28.793 回答