Is there a good reason why there is no Pair
in Java? What would be the equivalent of this C++ construct? I would rather avoid reimplementing my own.<
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");
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...
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().
Simple way Object [] - can be use as anу dimention tuple
Here are some libraries that have multiple degrees of tuples for your convenience:
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.
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 !