1. Overview

A tuple is a collection of several elements that may or may not be related to each other. In other words, tuples can be considered anonymous objects.

For example, [“RAM”, 16, “Astra”] is a tuple containing three elements.

In this tutorial, we’ll take a quick look at a really simple library, javatuples, that allows us to work with the tuple based data structures.

2. Built-in Javatuples Classes

This library provides us ten different classes that will suffice for most of our requirements related to tuples:

In addition to the classes above, there are two additional classes, KeyValue<A,B> and LabelValue<A,B>, which provide functionalities similar to Pair<A,B>, but that differ in semantics.

As per the official site, all the classes in javatuples are typesafe and immutable. Each of the tuple classes implements the Iterable, Serializable, and Comparable interface.

3. Adding Maven Dependency

Let’s add the Maven dependency to our pom.xml:

<dependency>
    <groupId>org.javatuples</groupId>
    <artifactId>javatuples</artifactId>
    <version>1.2</version>
</dependency>

Please check the Central Maven repository for the latest version.

4. Creating Tuples

Creating a tuple is really simple. We can use the corresponding constructors:

Pair<String, Integer> pair = new Pair<String, Integer>("A pair", 55);

There’s also a little less verbose and semantically elegant way of creating a tuple:

Triplet<String, Integer, Double> triplet = Triplet.with("hello", 23, 1.2);

We can also create tuples from an Iterable:

List<String> listOfNames = Arrays.asList("john", "doe", "anne", "alex");
Quartet<String, String, String, String> quartet
  = Quartet.fromCollection(collectionOfNames);

Please note that the number of items in the collection should match the type of the tuple that we want to create. For example, we can’t create a Quintet using the above collection, as it requires exactly five elements. The same is true for any other tuple class having a higher order than Quintet.

However, we can create a lower order tuple, like Pair or a Triplet, using the above collection by specifying a starting index in the fromIterable() method:

Pair<String, String> pairFromList = Pair.fromIterable(listOfNames, 2);

The above code will result in creating a Pair containing “anne” and “*alex.*”

Tuples can be conveniently created from any array as well:

String[] names = new String[] {"john", "doe", "anne"};
Triplet<String, String, String> triplet2 = Triplet.fromArray(names);

5. Getting Values From Tuples

Every class in javatuples has a getValueX() method for getting the values from tuples, where X specifies the order of the element inside the tuple. Like the indexes in arrays, the value of X starts from zero.

Let’s create a new Quartet, and fetch some values:

Quartet<String, Double, Integer, String> quartet 
  = Quartet.with("john", 72.5, 32, "1051 SW");

String name = quartet.getValue0();
Integer age = quartet.getValue2();
 
assertThat(name).isEqualTo("john");
assertThat(age).isEqualTo(32);

As we can see, the position of “john” is zero, “72.5” is one, and so on.

Note that the getValueX() methods are type-safe, which means no casting is required.

An alternative to this is the getValue(int pos) method. It takes a zero-based position of the element to be fetched. This method isn’t type-safe and requires explicit casting:

Quartet<String, Double, Integer, String> quartet 
  = Quartet.with("john", 72.5, 32, "1051 SW");

String name = (String) quartet.getValue(0);
Integer age = (Integer) quartet.getValue(2);
 
assertThat(name).isEqualTo("john");
assertThat(age).isEqualTo(32);

Please note that the classes KeyValue and LabelValue have their corresponding methods getKey()/getValue() and getLabel()/getValue().

6. Setting Values to Tuples

Similar to getValueX(), all classes in javatuples have setAtX() methods. Again, X is zero-based positions for the element that we want to set:

Pair<String, Integer> john = Pair.with("john", 32);
Pair<String, Integer> alex = john.setAt0("alex");

assertThat(john.toString()).isNotEqualTo(alex.toString());

The important thing here is that the return type of the setAtX() method is the tuple type itself. This is because the javatuples are immutable. Setting any new value will leave the original instance intact.

7. Adding and Removing Elements From Tuples

We can conveniently add new elements to the tuples; however, this will result in a new tuple of one order higher being created:

Pair<String, Integer> pair1 = Pair.with("john", 32);
Triplet<String, Integer, String> triplet1 = pair1.add("1051 SW");

assertThat(triplet1.contains("john"));
assertThat(triplet1.contains(32));
assertThat(triplet1.contains("1051 SW"));

It’s clear from the above example that adding one element to a Pair will create a new Triplet. Similarly, adding one element to a Triplet will create a new Quartet.

The example above also demonstrates the use of the contains() method provided by all the classes in javatuples. This is a really handy method for verifying if the tuple contains a given value.

It’s also possible to add one tuple to another using the add() method:

Pair<String, Integer> pair1 = Pair.with("john", 32);
Pair<String, Integer> pair2 = Pair.with("alex", 45);
Quartet<String, Integer, String, Integer> quartet2 = pair1.add(pair2);

assertThat(quartet2.containsAll(pair1));
assertThat(quartet2.containsAll(pair2));

Note the use of the containsAll() method. It’ll return true if all the elements of pair1 are present in quartet2.

By default, the add() method adds the element as a last element of the tuple. However, it’s possible to add the element at a given position using the addAtX() method, where X is the zero-based position where we want to add the element:

Pair<String, Integer> pair1 = Pair.with("john", 32);
Triplet<String, String, Integer> triplet2 = pair1.addAt1("1051 SW");

assertThat(triplet2.indexOf("john")).isEqualTo(0);
assertThat(triplet2.indexOf("1051 SW")).isEqualTo(1);
assertThat(triplet2.indexOf(32)).isEqualTo(2);

This example adds the String at position 1, which is then verified by the indexOf() method. Please note the difference in order of the types for the Pair<String, Integer> and the Triplet<String, String, Integer> after the call to the addAt1() method call.

We can also add multiple elements using any of the add() or addAtX() methods:

Pair<String, Integer> pair1 = Pair.with("john", 32);
Quartet<String, Integer, String, Integer> quartet1 = pair1.add("alex", 45);

assertThat(quartet1.containsAll("alex", "john", 32, 45));

In order to remove an element from the tuple, we can use the removeFromX() method. Again, X specifies the zero-based position of the element to be removed:

Pair<String, Integer> pair1 = Pair.with("john", 32);
Unit<Integer> unit = pair1.removeFrom0();

assertThat(unit.contains(32));

8. Converting Tuples to List/Array

We’ve already seen how to convert a List to a tuple. Now let’s see hot to convert a tuple to a List:

Quartet<String, Double, Integer, String> quartet
  = Quartet.with("john", 72.5, 32, "1051 SW");
List<Object> list = quartet.toList();

assertThat(list.size()).isEqualTo(4);

It’s fairly simple. The only thing to note here is that we’ll always get a List, even if the tuple contains the same type of elements.

Finally, let’s convert the tuple to an array:

Quartet<String, Double, Integer, String> quartet
  = Quartet.with("john", 72.5, 32, "1051 SW");
Object[] array = quartet.toArray();

assertThat(array.length).isEqualTo(4);

Clear enough, the toArray() method always returns an Object[].

9. Conclusion

In this article, we explored the javatuples library and observed it’s simplicity. It provides elegant semantics and is really easy to use.

Make sure to check out the complete source code for this article over on GitHub. The complete source code contains a few more examples than the ones covered here. After reading this article, the additional examples should be easy enough to understand.


« 上一篇: Java WebSocket API指南