Introduction to Java tuples
A tuple is a data structure that stores data in an ordered sequence like arrays or lists. But unlike arrays or lists, tuples can store data of different types.
For example, we can store ["string", 123, 123.321, 'c'] in a tuple but cannot use arrays or lists to store them. The only way this can be done using arrays or lists is by creating an array of strings and storing them using strings, but this could be very cumbersome.
String[] arr = {"string", "123", "123.321", "c"};
We can also create our own classes with data members of the required types and this can also lead to confusion and delay.
Java does not provide any data structure or collection that implements tuples, but we can add the external library called Java tuples to our project to use its tuple classes. It is a plain and simple library that provides different methods to work with tuples.
Java tuples Library
The Java tuples library provides ten different classes which can be used to work with tuples. The difference between these classes is the number of elements that can be stored in them. We cannot store more than 10 elements in a Java tuples class. The names of these classes are as follows.
- Unit<A> to store a single element.
- Pair<A, B> to store two elements.
- Triplet<A, B, C> to store three elements.
- Quartet<A, B, C, D> to store four elements.
- Quintet<A, B, C, D, E> to store five elements.
- Sextet<A, B, C, D, E, F> to store six elements.
- Septet<A, B, C, D, E, F, G> to store seven elements.
- Octet<A, B, C, D, E, F, G, H> to store eight elements.
- Ennead<A, B, C, D, E, F, G, H, I> to store nine elements.
- Decade<A, B, C, D, E, F, G, H, I, J> to store ten elements.
We also have two more classes called KeyValue<A, B> and LabelValue<A, B>. These are similar to the Pair<A, B> class. The alphabets A, B, C, etc, represent the datatypes of the different elements to be stored in the tuple.
All the tuple classes of this library are typesafe and immutable. We cannot change the data or the structure of the tuples after creating an object. All these classes implement the Iterable, Serializable, and Comparable interface.
Creating a Tuple in Java
Creating a tuple is pretty straightforward. We just need to specify the data types of the elements and their value to the class constructor.
import org.javatuples.*;
public class TupleDemo
{
public static void main(String[] args)
{
Triplet<String, Double, Integer> tuple1 = new Triplet<String, Double, Integer>("Str", 5.0, 5);
System.out.println(tuple1);
}
}
[Str, 5.0, 5]
We can also use the with() method to create a new tuple.
import org.javatuples.*;
public class TupleDemo
{
public static void main(String[] args)
{
Triplet<String, Double, Integer> tuple2 = Triplet.with("Str", 5.0, 5);
System.out.println(tuple2);
}
}
[Str, 5.0, 5]
We can also use the fromCollection() and fromIterable() methods to create a new tuple from a collection. Make sure to use the correct tuple class according to the size of the collection when using the fromCollection(). The fromIterable() method can be used to create a tuple of smaller size by specifying the index from where the elements should be picked.
import java.util.Arrays;
import java.util.List;
import org.javatuples.*;
public class TupleDemo
{
public static void main(String[] args)
{
List<String> list = Arrays.asList("unit","pair", "triplet");
Triplet<String, String, String> tuple1 = Triplet.fromCollection(list);
System.out.println(tuple1);
Pair<String, String> tuple2 = Pair.fromIterable(list, 1);//two elements to be fetched from index 1
System.out.println(tuple2);
}
}
[unit, pair, triplet]
[pair, triplet]
Fetching Values of Tuple in Java
We can use the getValue(X) or the getValueX() method to fetch an element present at the index X in the tuple. Just like arrays, tuples also follow zero-based indexing. Note that the getValue() method is not type-safe. We need to use casting when using this method. However, the getValueX() method is type-safe and does not require casting.
import org.javatuples.*;
public class TupleDemo
{
public static void main(String[] args)
{
Triplet<String, Integer, Double> tuple = Triplet.with("Str", 5, 5.0);
Integer i = (Integer)tuple.getValue(1);//casting
Integer j = tuple.getValue1();
System.out.println("Value fetched by getValue(): " + i);
System.out.println("Value fetched by getValueX(): " + j);
}
}
Value fetched by getValue(): 5
Value fetched by getValueX(): 5
Setting Values of Tuple in Java
We can change the value of an element in a tuple by using the setAtX() method where X is the index. This will return a tuple of the same class as the original tuple. Since tuples are immutable, the original tuple will not be altered in any way.
import org.javatuples.*;
public class TupleDemo
{
public static void main(String[] args)
{
Triplet<String, Integer, Double> tuple1 = Triplet.with("Str", 5, 5.0);
Triplet<String, Integer, Double> tuple2 = tuple1.setAt2(5.1);
System.out.println("Original Tuple: " + tuple1);
System.out.println("New Tuple with changes: " + tuple2);
}
}
Original Tuple: [Str, 5, 5.0]
New Tuple with changes: [Str, 5, 5.1]
Adding Elements in Tuple
We can add values to an existing tuple but we need to create a new tuple of larger size to accommodate the new element.
For example, if we add an element to a Septet class tuple, then we will get an Octet tuple.
We can add an element at the end of the tuple by using the add() method. Or we can use the addAtX() method to add an element at index X. This will push the other elements one place to the right. Make sure that the data types match up before inserting a new element.
import org.javatuples.*;
public class TupleDemo
{
public static void main(String[] args)
{
Triplet<String, String, String> tuple1 = Triplet.with("str1", "str2", "str3");
Quartet<String, String, String, String> tuple2 = tuple1.add("str4");
Quartet<String, String, String, String> tuple3 = tuple1.addAt0("str0");
System.out.println("Original Tuple: " + tuple1);
System.out.println("Adding using add(): " + tuple2);
System.out.println("Adding using addAtX(): " + tuple3);
}
}
Original Tuple: [str1, str2, str3]
Adding using add(): [str1, str2, str3, str4]
Adding using addAtX(): [str0, str1, str2, str3]
These two methods can also be used to add one tuple to another. We need to be careful about the resulting size of the new tuple. For example, if a Pair class tuple is added to a Triplet class tuple, then a Quintet tuple is created. Make sure that the combined size of the two tuples does not exceed 10.
import org.javatuples.*;
public class TupleDemo
{
public static void main(String[] args)
{
Triplet<String, String, String> tuple1 = Triplet.with("str1", "str2", "str3");
Pair<String, String> tuple2 = Pair.with("str4", "str5");
Quintet<String, String, String, String, String> tuple3 = tuple1.add(tuple2);
Quintet<String, String, String, String, String> tuple4 = tuple1.addAt1(tuple2);
System.out.println("Adding tuples using add(): " + tuple3);
System.out.println("Adding tuples using addAtX(): " + tuple4);
}
}
Adding tuples using add(): [str1, str2, str3, str4, str5]
Adding tuples using addAtX(): [str1, str4, str5, str2, str3]
Removing Elements
The removeFromX() method can be used to remove an element from index X. This will return a tuple of one size smaller than the original array. For example, when removeFromX() is used on a Quartet tuple, then a Triplet tuple is returned.
import org.javatuples.*;
public class TupleDemo
{
public static void main(String[] args)
{
Triplet<String, String, String> tuple1 = Triplet.with("str1", "str2", "str3");
Pair<String, String> tuple2 = tuple1.removeFrom0();
Pair<String, String> tuple3 = tuple1.removeFrom1();
System.out.println("Original Tuple: " + tuple1);
System.out.println("Removing element at index 0: " + tuple2);
System.out.println("Removing element at index 1: " + tuple3);
}
}
Original Tuple: [str1, str2, str3]
Removing element at index 0: [str2, str3]
Removing element at index 1: [str1, str3]
Looping/Iterating through a Tuple
Since tuples implement the Iterable interface, we can easily loop or iterate a Tuple using a simple for-each loop.
import org.javatuples.*;
public class TupleDemo
{
public static void main(String[] args)
{
Triplet<String, String, String> tuple = Triplet.with("str1", "str2", "str3");
for(Object o : tuple)
System.out.print(o + " ");
}
}
str1 str2 str3
Java tuples contains() and containsAll() Methods
The contains() method, as the name suggests, returns a boolean value according to the presence of an element in the tuple.
import org.javatuples.*;
public class TupleDemo
{
public static void main(String[] args)
{
Triplet<String, String, String> tuple = Triplet.with("str1", "str2", "str3");
boolean containsStr1 = tuple.contains("Str1");
boolean containsstr1 = tuple.contains("str1");
System.out.println("Tuple contains Str1: " + containsStr1);
System.out.println("Tuple contains str1: " + containsstr1);
}
}
Tuple contains Str1: false
Tuple contains str1: true
The containsAll() method can be used to check whether all elements of a collection are present in the tuple or not. This method also returns a boolean value.
import java.util.Arrays;
import java.util.List;
import org.javatuples.*;
public class TupleDemo
{
public static void main(String[] args)
{
Triplet<String, String, String> tuple = Triplet.with("str1", "str2", "str3");
List<String> list1 = Arrays.asList("str1", "str3", "str2");
List<String> list2 = Arrays.asList("str1", "str5", "str2");
System.out.println("Tuple contains list1: " + tuple.containsAll(list1));
System.out.println("Tuple contains list2: " + tuple.containsAll(list2));
}
}
Tuple contains list1: true
Tuple contains list2: false
Java tuples indexOf() and lastIndexOf() Methods
The indexOf() method returns the index of the first occurrence of an element in the tuple.
The lastIndexOf() method returns the index of the last occurrence of an element in the tuple.
import org.javatuples.*;
public class TupleDemo
{
public static void main(String[] args)
{
Quartet<String, String, String, String> tuple = Quartet.with("str1", "str2", "str1", "str3");
System.out.println("Tuple: " + tuple);
System.out.println("First index of str1:" + tuple.indexOf("str1"));
System.out.println("Last index of str1: " + tuple.lastIndexOf("str1"));
}
}
Tuple: [str1, str2, str1, str3]
First index of str1:0
Last index of str1: 2
Converting Tuples to Arrays or Lists
We can easily convert a tuple to an array by using the toArray() method. Similarly, we can use the toList() method to convert a tuple to a list. Note that these two methods will return arrays and lists of Object type(Object[] arr, List<Object> list) even if all the elements of the tuple have the same data type.
import java.util.Arrays;
import java.util.List;
import org.javatuples.*;
public class TupleDemo
{
public static void main(String[] args)
{
Quartet<String, String, String, String> tuple = Quartet.with("str1", "str2", "str1", "str3");
Object[] arrFromTuple = tuple.toArray();
List<Object> listFromTuple = tuple.toList();
System.out.println("Tuple: " + tuple);
System.out.println("Array: " + Arrays.toString(arrFromTuple));
System.out.println("List: " + listFromTuple);
}
}
Tuple: [str1, str2, str1, str3]
Array: [str1, str2, str1, str3]
List: [str1, str2, str1, str3]
Frequently Asked Questions
Q. How can tuples be implemented by using classes in Java?
Tuples are of fixed size and are used to store data of different types together. For example, if we want to store a string, an integer, and a double number, then we can create a class with these three data members and write appropriate constructors to create a new object of this type. But it is preferred to use external libraries like Java tuples.
Q. Are tuples faster than lists?
Yes, tuples are faster than lists because they are of fixed size and immutable, so we can just allocate a single block of memory to them and we don't need to add extra space for additional elements. Iterating over a tuple is also faster when compared to lists.
Summary
Tuples are an important data structure if we wish to assign data only once and never want to change that data again. They can be used to store records that contain fields of different data types like [101, "Chocolate", 5.99]. The Java tuples library provides different classes that can be used to work with tuples. The maximum number of elements that a tuple class can store is 10. A thing to note about tuples is that when we set, add, or remove values we are not altering the original tuple, instead, a new tuple is created with the modifications. This happens because tuples are immutable.