Groovy supports a tuple type. A tuple is an immutable object to store elements of potentially different types. In Groovy there is a separate Tuple class based on how many elements we want to store in the tuple. The range starts at Tuple0 and ends with Tuple16. So we can store a maximum of 16 elements in a Groovy tuple.
Each of the classes has a constructor that takes all elements we want to store. But the Tuple class also has static factory methods to create those classes. We can use the tuple method and based on how many elements we provide to this method we get the corresponding Tuple object.

To get the elements from a Tuple instance we can use specific properties for each element. The first element can be fetched using the v1 property, the second element is v2 and so on for each element. Alternatively we use the subscript operator ([]) where the first element is at index 0.

Each Tuple instance also has a subList and subTuple method where we can provide the from and to index values of the elements we want to be returned. The methods return a new Tuple with only the elements we requested.
A Groovy tuple is also a List and that means we can use all collection methods for a List also on a Tuple instance.

In the following example we create some tuples and use different methods:

// Using the constructor to create a Tuple.
def tuple2 = new Tuple2("Groovy", "Goodness")

// We can also use the static tuple method.
// Maximum number of elements is 16.
def tuple3 = Tuple.tuple("Groovy", "is", "great")

assert tuple3 instanceof Tuple3

// We can mix types as each elements can
// have it's own type.
def mixed = Tuple.tuple(30, "minutes")

// We can use the subscript operator ([])
// to get a value.
assert mixed[0] == 30
assert mixed[1] == "minutes"

// Or use the get() method.
assert mixed.get(0) instanceof Integer
assert mixed.get(1) instanceof String

// Or use the getter/property V1/V2.
// For each element in a Tuple we can use that.
// Notice that the first element starts with v1.
assert mixed.v1 == 30
assert mixed.getV2() == "minutes"

// Or use multiple assignments.
def (int minutes, String period) = mixed
assert minutes == 30
assert period == "minutes"

// We can get the size.
assert mixed.size() == 2

// Or transform the elements to an array
// and type information is saved.
assert mixed.toArray() == [30, "minutes"]

assert mixed.toArray()[0] == "java.lang.Integer"
assert mixed.toArray()[1] == "java.lang.String"

// Sample tuple with 4 elements.
Tuple4 tuple4 = Tuple.tuple("Groovy", "rocks", "as", "always")

// We can use subList or subTuple to create a new Tuple
// with elements from the original Tuple.
// We need to specify the "from" and "to" index.
// The "to" index is exclusive.
assert tuple4.subList(0, 2) == Tuple.tuple("Groovy", "rocks")
assert tuple4.subTuple(0, 2) == Tuple.tuple("Groovy", "rocks")

// As Tuple extends from List we can use all
// Groovy collection extensions.
assert tuple4.findAll { e -> e.startsWith("a") } == ["as", "always"]
assert tuple4.collect { e -> e.toUpperCase() } == ["GROOVY", "ROCKS", "AS", "ALWAYS"]

// We can even create an empty Tuple.
assert Tuple.tuple() instanceof Tuple0

Written with Groovy 4.0.11.