359

My Hashtable in Java would benefit from a value having a tuple structure. What data structure can I use in Java to do that?

Hashtable<Long, Tuple<Set<Long>,Set<Long>>> table = ...
n611x007
  • 8,952
  • 8
  • 59
  • 102
syker
  • 10,912
  • 16
  • 56
  • 68
  • 4
    You mean a pair, i.e. a tuple of length 2? In any case, I guess your best bet is to write a class of your own, shouldn't be too hard. –  Apr 19 '10 at 21:29
  • @Alexander, what if this particular Map needs safe concurrent access, then wouldn't Hashtable be the right choice? – maerics Apr 19 '10 at 22:04
  • 2
    I'd say wrapping with Collections.synchronizedMap(Map) would be preferable. – ColinD Apr 19 '10 at 22:08
  • 26
    If concurrent access is needed, then ConcurrentHashMap is the right class to use. It's more expressive and has better performance than a synchronized HashMap or Hashtable. – Esko Luontola Apr 19 '10 at 23:28
  • 3
    Maybe I've just seen too many Hashtables used when a HashMap should have been used... Collections.synchronizedMap at least signals that your intent is to synchronize. Though yeah, ConcurrentHashMap is even better. – ColinD Apr 20 '10 at 00:18
  • 4
    couldn't you just use AbstractMap.SimpleEntry, i have used this before when i want to achieve the Pair like behavior, out of the box. http://docs.oracle.com/javase/6/docs/api/java/util/AbstractMap.SimpleEntry.html – Nick Hecht Feb 07 '13 at 18:55
  • This is not asking for a tuple, this is a pair, or 2-tuple - as @doublep pointed out. Tuple [should be](https://en.wikipedia.org/wiki/Tuple) an ordered list of *n* elements where *n* is a non-negative integer. (Also, tuples are usually immutable.) – n611x007 Nov 05 '13 at 11:57
  • 1
    Could you edit the title so it's clear if it actually asks about Pairs, not tuples? A tuple is expected to be of n-length. The answers generally address the pair problem. They don't try to provide solutions for actual 'tuple', ie. an n-tuple. Because only Pair is needed to answer the question. And thus this way the question's title overlaps with an potential inquery about n-tuples in general. – n611x007 Nov 10 '13 at 17:12
  • 1
    can't you use the new java-14 `Record` type? – Daniel Pop Jul 28 '20 at 09:50

14 Answers14

362

I don't think there is a general purpose tuple class in Java but a custom one might be as easy as the following:

public class Tuple<X, Y> { 
  public final X x; 
  public final Y y; 
  public Tuple(X x, Y y) { 
    this.x = x; 
    this.y = y; 
  } 
} 

Of course, there are some important implications of how to design this class further regarding equality, immutability, etc., especially if you plan to use instances as keys for hashing.

maerics
  • 151,642
  • 46
  • 269
  • 291
  • 68
    I think it would be better to declare `x` and `y` as `public final` and get rid of those getters. –  Nov 10 '10 at 03:35
  • 64
    That is not a tuple. It only hold pairs (tuples of length 2). – Anoyz Jun 19 '12 at 10:59
  • 2
    I've used tuples a lot in C# and the documentation is really good if you would want to write a bigger one for your own: http://msdn.microsoft.com/de-de/library/vstudio/dd387036.aspx – Kjellski Oct 16 '12 at 12:18
  • 1
    -1 (sorry). as @Anoyz told, this is not a tuple - it is a 2-tuple or a pair. Tuples can be created with arbitrary number of elements. -- Your definition may be depending on where do you came from, I guess. – n611x007 Nov 05 '13 at 11:49
  • 27
    This doesn't work. When used in Hashtable or HashMap (as requested) it fails since 2 different tuples with the same elements will provide different hash codes. `equals()` and `hashCode()` must be overriden. – Yago Méndez Vidal Dec 12 '13 at 09:41
  • 47
    @YagoMéndezVidal: yes, the last sentence of my answer says "there are some important implications of how to design this class further regarding equality, immutability, etc., especially if you plan to use instances as keys for hashing." – maerics Dec 12 '13 at 14:17
  • 1
    @aem999 - The question you link to has been deleted. – RustyTheBoyRobot Jan 29 '14 at 23:00
  • 1
    @RustyTheBoyRobot updated link http://stackoverflow.com/questions/3642452/java-n-tuple-implementation – thisdotnull Mar 20 '14 at 13:51
  • @RustyTheBoyRobot I don't have sufficient privilege to update the link in the comment - the link has changed to: http://stackoverflow.com/questions/3642452/java-n-tuple-implementation – aem999 Dec 19 '14 at 02:31
  • Java 9+ : Entry pair = Map.entry(1, "a"); – GabrielBB Aug 12 '19 at 14:43
  • In JDK 14 onwards, you can use records to implement tuples. For example, `public record Pair(X x, Y y) {}`. You get tuple semantics for equality checks and hash code calculations out of the box. – bfdes Mar 29 '23 at 06:54
183

javatuples is a dedicated project for tuples in Java.

Unit<A> (1 element)
Pair<A,B> (2 elements)
Triplet<A,B,C> (3 elements)
Peter Lang
  • 54,264
  • 27
  • 148
  • 161
Daniel
  • 1,851
  • 1
  • 11
  • 2
  • 10
    Does it only cover tuples to 10-tuples? – n611x007 Nov 05 '13 at 11:50
  • 3
    @n611x007, I think every tuple variant is hand-written (i.e. you can't write java code with a variable number of type parameters, at least not easily), and so it makes sense for the library writer to stop somewhere, 10 seems like a reasonable number to support most use-cases. – gbmhunter Nov 14 '16 at 21:04
  • 3
    Some of the striking characteristics of the javatuple library as described in their website -- All tuple classes are: Typesafe, Immutable, Iterable, Serializable, Comparable (implements Comparable), Implementing equals(...) and hashCode(), and Implementing toString(). Might be useful to know. – dsapalo Mar 23 '17 at 13:33
  • 1
    Shame about their naming, especially the (unnecessary) `Unit`, which has different semantics from the `Unit` in Kotlin, Scala etc. – Rick-777 Jan 14 '20 at 13:49
118

Apache Commons provided some common java utilities including a Pair. It implements Map.Entry, Comparable and Serializable.

Eric
  • 19,525
  • 19
  • 84
  • 147
rhgb
  • 4,075
  • 2
  • 21
  • 28
  • 3
    The implementation provided by Apache Commons fulfills exactly what I needed. I am happy to have a working implementation. – Oliver Apr 30 '13 at 18:27
  • 7
    Well, the question seems to be wrong about tuples. Pairs != Tuples. Tuples are *n*-length, ie. any length. – n611x007 Nov 05 '13 at 12:03
  • 1
    @naxa please re-check the question description and you may found a `Pair` is exactly what he need. – rhgb Nov 10 '13 at 06:44
  • you are right in that and I may did wrong with pasting my view as comment in some answers, including yours. Unfortunatelly I tend to search questions based on their title; it's unclearness on the question's part that it uses a way more general title than the asker's actual problem. – n611x007 Nov 10 '13 at 17:07
  • 1
    @naxa: In a language where generic types are distinguishable by the number of parameters, it's fine to types called `Tuple`, `Tuple`, etc. The names are not good in Java, which does not allow such distinction, but that doesn't mean `Tuple` is not a good name for classes with hardcoded number of types in languages with "real" generic types. – supercat Mar 27 '14 at 22:20
  • 3
    Note for *Android developers* - Android SDK has already implement genric [Pair class](https://developer.android.com/reference/android/util/Pair.html) which supported from either API 5 or API 4 (support library). – Eido95 Nov 21 '16 at 17:20
  • I was excited to see that the `Pair` class in Apache Commons is in the `org.apache.commons.lang3.tuple` package, just to find out that a pair is the only type of tuple implemented :( – Matt Jul 17 '20 at 15:18
73

If you are looking for a built-in Java two-element tuple, try AbstractMap.SimpleEntry.

Dimitar
  • 4,402
  • 4
  • 31
  • 47
at7000ft
  • 901
  • 1
  • 8
  • 7
  • 53
    Less readable. If I saw this in code I'd wonder where the map is. – djechlin Oct 15 '13 at 17:27
  • 3
    While the intended purpose of this class is to facilitate the creation of custom map implementation according to the javadoc, this gets the job done nicely. +1. Also, readability isn't *that* big of an issue in this case. – scottysseus Oct 21 '15 at 18:24
  • 15
    If readability is a concern you could also create your own tuple like this: `class Tuple extends AbstractMap.SimpleEntry {}` Then you can refer to the class as `Tuple`. – yankee Jun 06 '16 at 09:39
  • @yankee if you're going through the trouble of creating your own class, why extend `AbstractMap.SimpleEntry`? Create your own type with exactly the semantics you need and your callers will expect. – dimo414 Dec 06 '17 at 06:44
  • 2
    @dimo414: Because SimpleEntry already implements equals, hashcode and has everything else one needs. If you want a generic `Tuple` then `key` and `value` maybe good names and the result might already be perfectly what you need. Of course if this is not the case then of course you are right that a custom implementation is a good idea. – yankee Dec 07 '17 at 22:02
  • This class is not immutable. Value (one of the elements of tuple) may be changed by setValue() method. – furkan Jan 06 '18 at 16:04
  • 1
    Furthermore accessing the elements of the tuple has to be done using `getKey` and `getValue` which is not really what you mean when you want a simple two element tuple. – Louis Caron Sep 12 '19 at 13:39
41

As an extension to @maerics nice answer, I've added a few useful methods:

public class Tuple<X, Y> { 
    public final X x; 
    public final Y y; 
    public Tuple(X x, Y y) { 
        this.x = x; 
        this.y = y; 
    }

    @Override
    public String toString() {
        return "(" + x + "," + y + ")";
    }

    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        }

        if (!(other instanceof Tuple)){
            return false;
        }

        Tuple<X,Y> other_ = (Tuple<X,Y>) other;

        // this may cause NPE if nulls are valid values for x or y. The logic may be improved to handle nulls properly, if needed.
        return other_.x.equals(this.x) && other_.y.equals(this.y);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((x == null) ? 0 : x.hashCode());
        result = prime * result + ((y == null) ? 0 : y.hashCode());
        return result;
    }
}
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Aram Kocharyan
  • 20,165
  • 11
  • 81
  • 96
30

Another 2 cents : Starting with Java 7, there is now a class for this in standard Lib : javafx.util.Pair.

And Yes, It is standard Java, now that JavaFx is included in the JDK :)

Teocali
  • 2,725
  • 2
  • 23
  • 39
17

Here's this exact same question elsewhere, that includes a more robust equals, hash that maerics alludes to:

http://groups.google.com/group/comp.lang.java.help/browse_thread/thread/f8b63fc645c1b487/1d94be050cfc249b

That discussion goes on to mirror the maerics vs ColinD approaches of "should I re-use a class Tuple with an unspecific name, or make a new class with specific names each time I encounter this situation". Years ago I was in the latter camp; I've evolved into supporting the former.

not-just-yeti
  • 17,673
  • 1
  • 18
  • 15
  • 4
    could you paste the relevant part here, before groups close down or anything? SO encourages copying relevant information to on-site. – n611x007 Nov 05 '13 at 11:53
  • 1
    If a method is supposed to examine a `double[]` and compute the minimum, maximum, average, and standard deviation, having it store the values into a passed-in `double[4]` may be less elegant than having it use a type with named fields, but someone who wants to know what's going on will *only* have to read the documentation for the method, instead of having to *also* read the documentation for a custom return type (or examine the code of it directly). Being able to return anonymous value types would be nicer, but Java doesn't support anything like that. Actually, if I had control over Java... – supercat Mar 27 '14 at 22:25
  • ...I'd add a few fields to `Thread` named `tempLong1`, `tempLong2`, `tempObject1`, `TempObject2`, etc. to minimize the number of temporary objects that need to be created purely for the purpose of being able to return more than one thing from a method. Icky, but there is no other clean solution. – supercat Mar 27 '14 at 22:29
17

With lombok it's easy to declare a Pair class:

@Data(staticConstructor = "of")
public class Pair<A, B> {
    private final A left;
    private final B right;
}

This will generates getters, static constructor named "of", equals(), hashcode() and toString().

see @Data documentation for more information

  • How does Iombok do this if the two fields A and B are final? – Lucas Crawford Jul 21 '15 at 05:45
  • check the sources on github, I personally don't know the internals. `final` here ensure we get a static constructor with "left" and "right" arguments and no setters –  Jul 21 '15 at 12:25
  • @LucasCrawford the fields are `final`, but the class isn't. You need the class to be extendable to do things like proxying. Also, `final`s carry only so much weight when reflection is considered (see `Class.setAccessible(boolean)`). – Milad Naseri Jan 03 '18 at 03:15
  • 1
    @user180100, re "with lombok it's easy to"; But is it easy to Lombok? – Pacerier May 16 '20 at 08:49
7

Android Tuple Utils

This object provides a sensible implementation of equals(), returning true if equals() is true on each of the contained objects.

see2851
  • 627
  • 1
  • 9
  • 13
7

Though the article is pretty old now, and though I understand that I'm not really very helpful, I think the proposal described in Adding tuples to Java: a study in lightweight data structures, would have been nice in mainstream Java.

You can do things like:

int a;
char b;
float c;
[a,b,c] = [3,'a',2.33];

or

[int,int,char] x = [1,2,'a'];

or

public [int,boolean] Find(int i)
{
  int idx = FindInArray(A,i);
  return [idx,idx>=0];
}

[idx, found] = Find(7);

Here tuples are:

  • Defined as primitive types - no templates/generics
  • Stack-allocated if declared locally
  • Assigned using pattern-matching

This approach increases

  • Performance
  • Readability
  • Expressiveness
Jacob van Lingen
  • 8,989
  • 7
  • 48
  • 78
  • 1
    Has there been any attempt to actually get this into standard Java? Or some project taking this a few steps further? – Hulk Feb 15 '15 at 12:35
  • 1
    The article above does reference a proprietary Java compiler which implements tuples. I don't think it's been considered in Standard Java though. – Mads Boyd-Madsen Feb 15 '15 at 12:50
  • 1
    I found a few references to this extension (named Spar/Java, it seems) in several research papers between 2001 and 2008. Would be interesting if anyone is still working on it (or why it was dropped if not). – Hulk Feb 15 '15 at 12:57
  • 2
    There is some activity in the Java community around this. See for instance: https://blogs.oracle.com/jrose/entry/tuples_in_the_vm – Mads Boyd-Madsen Feb 15 '15 at 13:19
6

Create a class that describes the concept you're actually modeling and use that. It can just store two Set<Long> and provide accessors for them, but it should be named to indicate what exactly each of those sets is and why they're grouped together.

ColinD
  • 108,630
  • 30
  • 201
  • 202
  • 1
    Ah, the question is just wrong. Are these ordered? Can have duplicate elements? What about a [tuple](https://en.wikipedia.org/wiki/Tuple)? ;) – n611x007 Nov 05 '13 at 12:04
  • Worth mentioning [Auto/Value](https://github.com/google/auto/tree/master/value) here - it makes creating your own types safe and painless. It's arguably *easier* than using a generic `Pair` or `Tuple` type. – dimo414 Dec 06 '17 at 06:46
5

To supplement @maerics's answer, here is the Comparable tuple:

import java.util.*;

/**
 * A tuple of two classes that implement Comparable
 */
public class ComparableTuple<X extends Comparable<? super X>, Y extends Comparable<? super Y>>
       extends Tuple<X, Y>
       implements Comparable<ComparableTuple<X, Y>>
{
  public ComparableTuple(X x, Y y) {
    super(x, y);
  }

  /**
   * Implements lexicographic order
   */
  public int compareTo(ComparableTuple<X, Y> other) {
    int d = this.x.compareTo(other.x);
    if (d == 0)
      return this.y.compareTo(other.y);
    return d;
  }
}
Alexei Averchenko
  • 1,706
  • 1
  • 16
  • 29
3

You can use Google Guava Table

patstuart
  • 1,931
  • 1
  • 19
  • 29
Ste
  • 141
  • 1
  • 8
1

I will start from a general point of view about tuples in Java and finish with an implication for your concrete problem.

1) The way tuples are used in non-generic languages is avoided in Java because they are not type-safe (e.g. in Python: tuple = (4, 7.9, 'python')). If you still want to use something like a general purpose tuple (which is not recommended), you should use Object[] or List<Object> and cast the elements after a check with instanceof to assure type-safety.

Usually, tuples in a certain setting are always used the same way with containing the same structure. In Java, you have to define this structure explicitly in a class to provide well-defined, type-safe values and methods. This seems annoying and unnecessairy at first but prevents errors already at compile-time.

2) If you need a tuple containing the same (super-)classes Foo, use Foo[], List<Foo>, or List<? extends Foo> (or the lists's immutable counterparts). Since a tuple is not of a defined length, this solution is equivalent.

3) In your case, you seem to need a Pair (i.e. a tuple of well-defined length 2). This renders maerics's answer or one of the supplementary answers the most efficient since you can reuse the code in the future.

Mario Reutter
  • 249
  • 2
  • 10
  • 9
    Tuples are not safe? That's bs. Look at C++ tuples for example (not to mention Haskell, Scala and others). If container can store values of different types, doesn't mean it is not type-safe. If anything, it's Java's limitations that prevent implementation of proper tuples. – Dan M. Jul 18 '16 at 23:49
  • 8
    @DanM. you are right. I edited my response accordingly to explicitly refer to non-generic languages only. Please consider to phrase your comments in a polite way. – Mario Reutter Jul 20 '16 at 13:25