17

Just attempting this question I found in a past exam paper so that I can prepare for an upcoming Java examination.

Provide a generic class Pair for representing pairs of things. The class should provide a constructor, a method for getting the first member of the pair, a method for getting the second member of the pair, a method for setting the first member of the pair, a method for setting the second member of the pair. The class should be parameterised over two types one for the first member and one for the second member of the pair.

Is this a correct implementation for this question ?

public class Pair<firstThing, secondThing>{
   private firstThing first;//first member of pair
   private secondThing second;//second member of pair

   public Pair(firstThing first, secondThing second){
     this.first = first;
     this.second = second;
   }

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

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

   public thing getFirst() {
     return this.first;
   }

   public thing getSecond() {
     return this.second;
   }
}
j0k
  • 22,600
  • 28
  • 79
  • 90
John Curtsy
  • 541
  • 3
  • 8
  • 15
  • 2
    Please when you edit your question, highlight your edits. The answers become confusing when you don't. – Jan Zyka May 18 '11 at 13:01
  • 1
    Not to be snarky, but in English, "pair" generally implies two things which are alike (same type). The CS term for what you're describing is "tuple". – CPerkins May 18 '11 at 13:41
  • 1
    @CPerkins: I always thought that *pair* is simply another word for *2-tuple*. – Paŭlo Ebermann May 18 '11 at 13:45
  • As Boris pointed, the getters are fully broken. Both `thing` as variable and `thing` as return type are wrong. `public firstThing getFirst() { return this.first; }` – Kobor42 Aug 12 '12 at 17:28
  • Or you could use Entry, see: http://stackoverflow.com/questions/521171/a-java-collection-of-value-pairs-tuples – Josep Valls Feb 18 '17 at 00:27

17 Answers17

25

Almost. I'd write it like this:

public class Pair<F, S> {
    private F first; //first member of pair
    private S second; //second member of pair

    public Pair(F first, S second) {
        this.first = first;
        this.second = second;
    }

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

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

    public F getFirst() {
        return first;
    }

    public S getSecond() {
        return second;
    }
}

Edit: I agree with @karmakaze's comment. The code should skip the setters and make first and second final to keep it immutable.

Claes Mogren
  • 2,126
  • 1
  • 26
  • 34
  • 14
    I would generally make it immutable without the 'set' methods. – karmakaze May 18 '11 at 20:26
  • Can you explain the difference between your code and the OP's code? – einpoklum Mar 04 '15 at 16:10
  • 1
    Not much of a difference, besides that the standard java convention for a type name is a single capital letter (F and S in this example) and that the getters return typed values of that type. But, again as @karmakaze said, I should have made the variables final and have no setters. – Claes Mogren Mar 04 '15 at 19:54
  • How can I get the class for this Class? Example int.class will return the int class. How can I do it for this class to get class of Pair? – Mohammed Julfikar Ali Mahbub Oct 22 '19 at 13:26
11

The need for a Pair class usually crops up in larger projects - I'm about to (re)implement one for the current project (as previous implementations are not accessible).

Generally I make it an immutable POJO, with a convenience function to create instances. For example:

public class Pair<T,U>
{
    public final T first;
    public final U second;
    public static <T,U> Pair<T,U> of(T first, U second);
}

So that the end-user can write:

return Pair.of (a, b);

and

Pair<A,B> p = someThing ();
doSomething (p.first);
doSomethingElse (p.second);

As mentioned above, the Pair class should also implement hashCode(), equals(), optional-but-useful toString(), as possibly clone() and compareTo() for use where these are supported by T and U - though extra work is required to describe how these contracts are supported by the Pair class.

Gavriel
  • 18,880
  • 12
  • 68
  • 105
simon.watts
  • 976
  • 10
  • 14
5

You can look to implementation of standard Java classes AbstractMap.SimpleEntry and AbstractMap.SimpleImmutableEntry. It is pretty easy to google sources:

gavenkoa
  • 45,285
  • 19
  • 251
  • 303
5

Here is an implementation from the Android SDK

/**
 * 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.equal(p.first, first) && Objects.equal(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);
    }
}
pommedeterresautee
  • 1,843
  • 1
  • 20
  • 24
3

I think No. Quote:

"the class should be parameterised over two types..."

I think they are expecting in terms of :

public class Pair<ThingA, ThingB>
Suraj Chandran
  • 24,433
  • 12
  • 63
  • 94
2

Usually a generic Pair type has two generic type parameters, not one - so you could have (say) a Pair<String, Integer>. That's typically more useful, IMO.

I would also suggest that you think about a more conventional name for your type parameter than "thing". For example, you might use Pair<A, B> or Pair<T, U>.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
2

Getters are broken

public thing getFirst() {
  return thing.first;
}

public thing getSecond() {
  return thing.second;
}

thing should be replaced with this

Boris Pavlović
  • 63,078
  • 28
  • 122
  • 148
2

After editing, it looks good.

However, you really should implement the hashCode and equals methods, so that two pairs containing the same objects will be equal to each other, and can be used as keys in a HashMap. And toString if you're feeling generous. These methods are not required to fulfil the requirements you've been given, but they are things a good programmer would add.

Tom Anderson
  • 46,189
  • 17
  • 92
  • 133
1

Apache Commons Lang has a generic pair implementation

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

raghu
  • 95
  • 1
  • 10
1

The class should be parameterised over two types one for the first member and one for the second member of the pair.

You have only one parameter.

you need something like Pair<F,S> and use F where you use thing for first and S where thing for second.

Jan Zyka
  • 17,460
  • 16
  • 70
  • 118
1

No. Have you tried coding it to see if it works?

You seem to have missed this part of the requirement:

The class should be parameterised over two types one for the first member and one for the second member of the pair.

Which means the class should probably be defined as something more like:

public class Pair<T1, T2>

and the other methods updated accordingly. (By the way, I've used T1 and T2 to refer to the types as by convention a short - 1 or 2 char - identifier is used).

Also,

return thing.first;

and

return thing.second;

are not going to work, as in your example, thing is a type, not an object. Think about what you want to return here. Do you even need to call a method?

Once you've made your changes, code it and either write a unit test or a simple test-harness to check if it works.

Russell
  • 12,261
  • 4
  • 52
  • 75
0

My version of Pair. This also handles compares. PS : Most of the code is taken from AOSP.

package util;

import java.util.Objects;

public class Pair<F extends Comparable<F>, S extends Comparable<S>>
  implements Comparable<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 extends Comparable<A>, B extends Comparable<B>> Pair<A, B> create(A a, B b) {
        return new Pair<>(a, b);
    }

    @Override
    public int compareTo(Pair<F, S> that) {
        int cmp = this.first.compareTo(that.first);
        if (cmp == 0)
            cmp = this.second.compareTo(that.second);
        return cmp;
    }
}
Tom
  • 16,842
  • 17
  • 45
  • 54
Brajesh Kumar
  • 929
  • 6
  • 16
0

I implemented something similar but with static builder and chained setters

public class Pair<R, L> {

private R left;
private L right;

public static <K,V> Pair<K, V> of(K k, V v) {
    return new Pair<K,V>(k, v);
}

public Pair() {}

public Pair(R key, L value) {
    this.left(key);
    this.right(value);
}

public R left() {
    return left;
}

public Pair<R, L> left(R key) {
    this.left = key;
    return this;
}

public L right() {
    return right;
}

public Pair<R, L> right(L value) {
    this.right = value;
    return this;
}
}
Rodrigo Asensio
  • 2,760
  • 4
  • 26
  • 26
0

thing is a Type Variable in an unsual notation - we usually use one uppercase latter (like T). Then: a type variable does not have any methods, so your getters won't compile.

Quick improvement: replace all thing with T

Quick fix for getters:

public T getFirst() {
 return first;
}

public T getSecond() {
 return second;
}

One requirement was to allow two different types for the pair members. So the class signature should look like:

public Pair<S,T> {
  private S first;
  private T second;
  //...
}
Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
0

Creating a Generic Pair class takes much time. Using SimpleEntry will be much easier.

static class Pair {
    public static <T, U> Map.Entry<T, U> of(T first, U second) {
        return new AbstractMap.SimpleEntry<>(first, second);
    }
}
iamcrypticcoder
  • 2,609
  • 4
  • 27
  • 50
0

In java 17, we can use record:

record Pair<F, S>(F first, S second) {
  public static <F, S> Pair<F, S> of(F first, S second) {
    return new Pair<>(first, second);
  }
}
0

Since Java 17, record is a simple way to achieve this:

/**
 * Pair data structure.
 *
 * @param first  first entry
 * @param second second entry
 * @param <F>    type of first entry
 * @param <S>    type of second entry
 */
public record Pair<F, S>(F first, S second) {
}

Use it as follows:

Pair<Long, String> myPair = new Pair<>(4L, "Four");
System.out.println(myPair);

Output:

Pair[first=4, second=Four]

DaHoC
  • 314
  • 1
  • 4
  • 14