132

Am I remembering incorrectly, or did Java, once upon a time, provide a Pair class as part of its API?

Sled
  • 18,541
  • 27
  • 119
  • 168
Alexx
  • 3,572
  • 6
  • 32
  • 39
  • I'm pretty sure that in early versions one of the base classes -- Hashtable or some such -- had a non-public helper class that was a Pair (this was before inner classes). – Hot Licks Oct 03 '13 at 01:01

10 Answers10

99

There is no Pair in the standard framework, but the Apache Commons Lang, which comes quite close to “standard”, has a Pair.

new MutablePair<>(1, "xxx");
new ImmutablePair<>(1, "xxx");
Pavel Vlasov
  • 4,206
  • 6
  • 41
  • 54
Josh Lee
  • 171,072
  • 38
  • 269
  • 275
  • 3
    Pair pair = new ImmutablePair(key, value); – user77115 Nov 15 '12 at 10:38
  • 3
    If you happen to be developing for Android.. it has `Pair` also – Tim Mar 20 '15 at 17:44
  • 3
    Or even simpler: Pair pair = Pair.of(key, value); – Edu Castrillon Nov 26 '15 at 12:54
  • 4
    Have a look @gavenkoa's answer below. `java.util.Map.Entry` may be a simple solution. – Jacek Dec 18 '15 at 01:47
  • Unfortunately the Pair implementation of android is immutable. – JacksOnF1re Apr 29 '16 at 16:04
  • 2
    This answer is incomplete(and wrong) but unfortunately ranked highest as of seen today. Till JDK 10(and from Javafx 2.0) it had Pair class https://docs.oracle.com/javase/10/docs/api/javafx/util/Pair.html. But it was in javafx.util package Not java.util which got many confused. With JDK 11, JavaFX being noncore module got separated from JDK so one cannot find(and yes surprised) Pair class after that. https://www.infoworld.com/article/3305073/removed-from-jdk-11-javafx-11-arrives-as-a-standalone-module.html – nanosoft Jun 05 '21 at 09:16
79

Map.Entry

Java 1.6 and upper have two implementation of Map.Entry interface pairing a key with a value:

UML diagram of SimpleEntry & SimpleImmutableEntry classes inheriting from Map.Entry interface

For example

Map.Entry < Month, Boolean > pair = 
    new AbstractMap.SimpleImmutableEntry <>( 
        Month.AUGUST , 
        Boolean.TRUE 
    )
;

pair.toString(): AUGUST=true

I use it when need to store pairs (like size and object collection).

This piece from my production code:

public Map<L1Risk, Map.Entry<int[], Map<L2Risk, Map.Entry<int[], Map<L3Risk, List<Event>>>>>>
        getEventTable(RiskClassifier classifier) {
    Map<L1Risk, Map.Entry<int[], Map<L2Risk, Map.Entry<int[], Map<L3Risk, List<Event>>>>>> l1s = new HashMap<>();
    Map<L2Risk, Map.Entry<int[], Map<L3Risk, List<Event>>>> l2s = new HashMap<>();
    Map<L3Risk, List<Event>> l3s = new HashMap<>();
    List<Event> events = new ArrayList<>();
    ...
    map.put(l3s, events);
    map.put(l2s, new AbstractMap.SimpleImmutableEntry<>(l3Size, l3s));
    map.put(l1s, new AbstractMap.SimpleImmutableEntry<>(l2Size, l2s));
}

Code looks complicated but instead of Map.Entry you limited to array of object (with size 2) and lose type checks...

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
gavenkoa
  • 45,285
  • 19
  • 251
  • 303
37

A Pair class :

public class Pair<K, V> {

    private final K element0;
    private final V element1;

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

    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 !

Bastiflew
  • 1,136
  • 3
  • 18
  • 31
  • Nice! I'm not sure why I thought Java had a Pair class, but I could have sworn it did at one point in its history. I must be confusing it with another language. – Alexx Dec 13 '11 at 05:57
  • 2
    If you've worked on Android projects (java based) then you've probably used their [Pair Class](http://developer.android.com/reference/android/util/Pair.html) – ainesophaur Feb 26 '14 at 06:29
17

There are lots of implementation around here, but all the time something is missing , the Override of equal and hash method.

here is a more complete version of this class:

/**
 * Container to ease passing around a tuple of two objects. This object provides a sensible
 * implementation of equals(), returning true if equals() is true on each of the contained
 * objects.
 */
public class Pair<F, S> {
    public final F first;
    public final S second;

    /**
     * Constructor for a Pair.
     *
     * @param first the first object in the Pair
     * @param second the second object in the pair
     */
    public Pair(F first, S second) {
        this.first = first;
        this.second = second;
    }

    /**
     * Checks the two objects for equality by delegating to their respective
     * {@link Object#equals(Object)} methods.
     *
     * @param o the {@link Pair} to which this one is to be checked for equality
     * @return true if the underlying objects of the Pair are both considered
     *         equal
     */
    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Pair)) {
            return false;
        }
        Pair<?, ?> p = (Pair<?, ?>) o;
        return Objects.equals(p.first, first) && Objects.equals(p.second, second);
    }

    /**
     * Compute a hash code using the hash codes of the underlying objects
     *
     * @return a hashcode of the Pair
     */
    @Override
    public int hashCode() {
        return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
    }

    /**
     * Convenience method for creating an appropriately typed pair.
     * @param a the first object in the Pair
     * @param b the second object in the pair
     * @return a Pair that is templatized with the types of a and b
     */
    public static <A, B> Pair <A, B> create(A a, B b) {
        return new Pair<A, B>(a, b);
    }
}
MartyIX
  • 27,828
  • 29
  • 136
  • 207
pommedeterresautee
  • 1,843
  • 1
  • 20
  • 24
  • 6
    It looks like a copy/paste from AOSP (why not to add credit or reference?). To make it a complete version, at least replace the Objects#equal convenience method with actual implementation. – Alex Lipov Apr 21 '15 at 11:51
  • Needs to change "return Objects.equal(p.first, first) && Objects.equal(p.second, second);" to "return Objects.equals(p.first, first) && Objects.equals(p.second, second);" – Amir Katz May 05 '15 at 07:45
16

This should help.

To sum it up: a generic Pair class doesn't have any special semantics and you could as well need a Tripplet class etc. The developers of Java thus didn't include a generic Pair but suggest to write special classes (which isn't that hard) like Point(x,y), Range(start, end) or Map.Entry(key, value).

Community
  • 1
  • 1
Thomas
  • 87,414
  • 12
  • 119
  • 157
13

No, but it's been requested many times.

Wayne
  • 59,728
  • 15
  • 131
  • 126
5

Many 3rd party libraries have their versions of Pair, but Java has never had such a class. The closest is the inner interface java.util.Map.Entry, which exposes an immutable key property and a possibly mutable value property.

Dilum Ranatunga
  • 13,254
  • 3
  • 41
  • 52
4

No but JavaFX has it.

Cf. Stack Overflow: Java Pair class implementation

Community
  • 1
  • 1
lamusique
  • 392
  • 4
  • 6
3

It does seem odd. I found this thread, also thinking I'd seen one in the past, but couldn't find it in Javadoc.

I can see the Java developers' point about using specialised classes, and that the presence of a generic Pair class could cause developers to be lazy (perish the thought!)

However, in my experience, there are undoubtedly times when the thing you're modelling really is just a pair of things and coming up with a meaningful name for the relationship between the two halves of the pair, is actually more painful than just getting on with it. So instead, we're left to create a 'bespoke' class of practically boiler-plate code - probably called 'Pair'.

This could be a slippery slope, but a Pair and a Triplet class would cover a very large proportion of the use-cases.

3

If you want a pair (not supposedly key-value pair) just to hold two generic data together neither of the solutions above really handy since first (or so called Key) cannot be changed (neither in Apache Commons Lang's Pair nor in AbstractMap.SimpleEntry). They have thier own reasons, but still you may need to be able to change both of the components. Here is a Pair class in which both elements can be set

public class Pair<First, Second> {
    private First first;
    private Second second;

    public Pair(First first, Second second) {
        this.first = first;
        this.second = second;
    }

    public void setFirst(First first) {
        this.first = first;
    }

    public void setSecond(Second second) {
        this.second = second;
    }

    public First getFirst() {
        return first;
    }

    public Second getSecond() {
        return second;
    }

    public void set(First first, Second second) {
        setFirst(first);
        setSecond(second);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Pair pair = (Pair) o;

        if (first != null ? !first.equals(pair.first) : pair.first != null) return false;
        if (second != null ? !second.equals(pair.second) : pair.second != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = first != null ? first.hashCode() : 0;
        result = 31 * result + (second != null ? second.hashCode() : 0);
        return result;
    }
}
hevi
  • 2,432
  • 1
  • 32
  • 51
  • For immutable, how about [`AbstratMap.SimpleImmutableEntry`](https://docs.oracle.com/javase/8/docs/api/java/util/AbstractMap.SimpleImmutableEntry.html)? – Basil Bourque Apr 04 '16 at 23:41
  • problem with collection pairs is that, collections such as hashmap uses key for inserting and getting the vaue, you cannot change the key. if you want a pair, with a key and value, both changeable then you cant use AbstratMap.SimpleImmutableEntry, as i mentioned in the solution. – hevi Apr 05 '16 at 08:22