Using javatuples

The tuple classes

There are ten tuple classes in javatuples:

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

Plus a couple of very common 2-element tuple classes equivalent to Pair, just for the sake of code semantics:

  • KeyValue<A,B>
  • LabelValue<A,B>

All tuple classes are:

  • Typesafe
  • Immutable
  • Iterable
  • Serializable
  • Comparable (implements Comparable<Tuple>)
  • Implementing equals(...) and hashCode()
  • Implementing toString()

Creating tuples

Tuples can be instanced in a semantically elegant way, using the with(...) methods from each of the tuple classes:

    Pair<String,Integer> pair = Pair.with("hello", Integer.valueOf(23));
    ...
    Quintet<String,Integer,Double,String,String> quintet = 
        Quintet.with("a", Integer.valueOf(3), Double.valueOf(34.2), "b", "c"); 

Of course, constructors can also be used directly:

    Pair<String,Integer> pair = new Pair<String,Integer>("hello", Integer.valueOf(23));
    ...
    Quintet<String,Integer,Double,String,String> quintet = 
        new Quintet<String,Integer,Double,String,String>("a", Integer.valueOf(3), Double.valueOf(34.2), "b", "c"); 

You can also create tuples from collections or --more generally--, any iterable:

    Quintet<String,String,String,String,String> quintet = Quintet.fromCollection(myCollectionWith5Elements);
    ...
    // Retrieve three values from an iterable starting at a specific index
    Triplet<Integer,Integer,Integer> triplet = Triplet.fromIterable(lotsOfInts, 7);

Getting values

Values can be retrieved from a tuple by using the specific method for its position:

    Triplet<String,Integer,Double> triplet = ...
    ...
    Integer intVal = triplet.getValue1();

Note that:

  • Value numbering starts with 0, so the getter for the first position will always be getValue0().
  • A tuple object will only offer you methods for the specific number of positions it holds (e.g. Quartet does not have a getValue4() method).
  • All getValueX() getters are typesafe, no cast needed. Thanks to the type parameterization of the tuple classes (the "<A,B,C,D>" in Quartet<A,B,C,D>) the compiler will know that value0 is of type A, value1 of type B, and so on.

There is also a getValue(int pos) method, but its use is not recommended, because the compiler cannot know the type of the result beforehand and therefore you will need a cast:

    Triplet<String,Integer,Double> triplet = ...
    ...
    Integer intVal = (Integer) triplet.getValue(1);

Note that classes KeyValue and LabelValue have their getValue0()/getValue1() methods renamed as getKey()/getValue() and getLabel()/getValue(), respectively.

Setting new values

In order to set new values for specific positions of a tuple, you can use the setAtX(...) setter methods:

    Triplet<String,Integer,Double> triplet = ...
    ...
    triplet = triplet.setAt2(Double.valueOf(245.21));

Important: tuples are immutable. This means that you will have to collect the return value of your setAtX(...) calls, and also that you will be able to change the type of a position in the tuple by changing the object that lives in that position:

    Triplet<String,Integer,Double> triplet = ...
    ...
    Triplet<String,Integer,String> otherTriplet = triplet.setAt2("North Atlantic");

Adding or removing elements

New elements can be added to a tuple, converting it in a different tuple.

For example, if you add a String to a Triplet<String,Integer,Double>, you will turn it into a Quartet<String,Integer,Double,String>:

    Triplet<String,Integer,Double> triplet = ...
    ...
    Quartet<String,Integer,Double,String> quartet = triplet.add("South Pacific");

By default, new elements are added at the end of the tuple. But you can also add elements in other positions of the tuple by using the addAtX(...) methods:

    Triplet<String,Integer,Double> triplet = ...
    ...
    Quartet<String,Integer,String,Double> quartet = triplet.addAt2("Mediterranean");

You can also add more than one element...

    Triplet<String,Integer,Double> triplet = ...
    ...
    Quintet<String,Integer,String,String,Double> quintet = triplet.addAt2("Red Sea", "Caspian");

...or even other tuples:

    Triplet<String,Integer,Double> triplet1 = ...
    Triplet<Byte,String[],String> triplet2 = ...
    ...
    Sextet<String,Integer,Byte,String[],String,Double> sextet = triplet1.addAt2(triplet2);

Removing elements is just as easy, and it will also transform your tuple. If you remove an element from a Triplet, you will get a Pair:

    Triplet<String,Integer,Double> triplet = ...
    ...
    Pair<String,Double> pair = triplet.removeFrom1();

Converting to/from collections or arrays

A tuple can be easily converted to a list or an array, but you will lose your type-safety and end up with a List<Object> or an Object[]:

    Triplet<String,Integer,Double> triplet = ...
    ...
    List<Object> list = triplet.toList();
    ...
    Object[] array = triplet.toArray();

Inversely, you can obtain a tuple from both a collection or an array:

    String[] array = ...
    ...
    Quartet<String,String,String,String> quartet = Quartet.fromArray(array); 

Note that your tuple will have all its elements set to the component type of the array (String, in this case). Also, note that...

    String[] array = new String[] { "a", "b", "c", "d", "e" };
    ...
    // Array has five elements: will raise an exception trying to create a quartet!!
    Quartet<String,String,String,String> quartet = Quartet.fromArray(array); 

...will raise the following exception:

    java.lang.IllegalArgumentException: Array must have exactly 4 elements in order to create a Quartet. Size is 5
            at ...

Iterating

All tuple classes in javatuples implement the Iterable<Object> interface, so it can be iterated in the same way as collections or arrays:

    Triplet<String,Integer,Double> triplet = ...
    ...
    for (Object value : tuple) {
        ...
    }

Checking contents

Tuples offer some utility methods, like contains(...), containsAll(...), indexOf(...) or lastIndexOf(...), which work in exactly the same way as they do in collections:

    Quartet<String,Integer,String,Boolean> quartet = ...
    ...
    if (quartet.contains(value)) {
        ...
    }
    ...
    if (quartet.containsAll(valueCollection)) {
        ...
    }