Do you need tuples in Java?

I asked myself: Do you really need tuples in Java? In a broader sense: How much generalization do you need to solve a certain problem? Since I came across this issue lately and thought I needed a data structure to hold a set of objects with completely different types let’s have a closer look at this.

How comes?

What are tuples to begin with? In the context of programming languages -- and in my examples Java in particular -- tuples can in turn hold different kinds of data types.

For example this Tuple2 class can be parameterized to hold a String and an Integer value.

private class Tuple2<A, B> {
  public A a;
  public B b;
}

As you can see the class itself does not carry any domain specific information. It’s just a general purpose class that you can use in all different kinds of scenarios.

Of course, you can come up with a Tuple3 class and add more properties to the class.

private class Tuple3<A, B, C> {
  public A a;
  public B b;
  public C c;
}

You can even mix the different tuple classes and create a data structure that may make sense in your specific use case. The data that is actually stored in the properties of a tuple class does not necessarily have to be related. You can store whatever you want in it as the general names of the properties do not suggest any special meaning.

By the way, you do not even need classes to model tuples in Java. You can just use arrays for that purpose and this looks like the following:

Object[] myTuple = { 42, "foo", Collections.EMPTY_LIST };

This creates an array of Objects and so you can put whatever you want in it like an Integer, a String or even a List.

Some overview

Now that we had a first quick look how tuples might work in Java let’s check out some alternatives.

I want to start with C# as the .NET Framework documentation features different Tuple classes.

The C++11 standard proposed a Tuple type and similar to our example in Java at the beginning these tuples can hold different types of data.

Again in Java we have the SimpleEntry class in AbstractMap that you can abuse as a Tuple with two elements if you want to.

Part of JavaFX is a Pair class that also can be used as such a Tuple with two properties.

Then there are libraries like Apache Commons Lang3. It contains a Pair or Triple class.

On javatuples.org you can find a library that has a lot of different tuples like Pair, Triplet and up to Decade.

Then there is Vavr that contains Tuple1, 2, 3 and up to Tuple8 classes for that purpose.

The Scala library has Tuple1, Tuple2 and even up to Tuple22 classes.

As you can see there are a lot of solutions to choose from.

Ask the Internet

But how about asking the Internet whether Tuples are a good idea or not.

Over at StackOverflow among many others you can find this questions about an equivalent of the C++ Pair in Java. The answer with the most upvotes refers to a thread on comp.lang.java.help where a user basically asks about tuples in Java. After a few examples somebody says that the semantics of these general classes do not convey the meaning or the intent behind a certain piece of code. He suggests to use meaningful names instead. Later on he gives a few reasonable examples like Position, Size or Range instead of a Tuple with two elements.

Like with all good discussion threads somebody thinks that it’s a great idea to post his Java crash report asking for advice how to fix this. He gets a calm response and the discussion ends there.

Another question about tuples on StackOverflow points to Google Guava and the old page IdeaGraveyard about ideas that they have rejected and have not added to the library. Just like the discussion on comp.lang.java.help they come to the same conclusion that Tuple classes obfuscate the real meaning and thus make the code harder to read.

But when might you want to use Tuples then? There may be other valid use cases but I want to focus on two possible scenarios and the corresponding alternatives in Java. First, when using Tuples as input parameters for methods. And second, when returning data in some sort of data structure.

Input and output

Let’s imagine that you have a method that needs two Integer parameters because you want to return the sum of both values. With Lambda expressions in Java you can write an implementation of the BiFuntion like so.

But if you want to add three values you will notice that the standard Java API hasn’t got a TriFunction interface. That’s where the concept of Currying comes into play. This allows you to rewrite your implementation -- again using Lambda expressions -- in such a way that you only need the Function interface.

If you want to you can apply the same concept to a function with three parameters. Of course the input parameters do not have to be of the same type. So instead of writing a method with a long signature and a lot of parameters or just one input parameter but modeled as a Tuple that holds the necessary data you can use Currying to setup your method in such a way that a chain of method calls hand the necessary parameters over from one to the other. Finally you can then construct your result.

In my second example we will have a look at returning data from a method call. In the Java world Data Transfer Objects are often used to combine certain data from your domain objects and prepare it for example for the view layer of your application.

As a quick side note this was not the original pattern for DTOs. But the idea to use DTOs in this way for your presentation model can be okay if your domain model does not exactly fit the view that you want to show the user of your application. DTOs can be a good layer of abstraction in this case.

Anyway, let’s think about a method that returns the x and y coordinates of a certain area. Instead of returning a Tuple with two elements you can argue that it’s much more intuitive to use a class named Position that holds the values for x and y.

The same can be applied to data transfer objects. Instead of returning a generic tuple with, let’s say, five elements you can come up with a more specific class that helps you and everybody else to understand the intent of the data that is returned.

Conclusion

Tuples in this sense come across as a way of over generalization that you may not need in your code. As I said, there may be use cases where a Tuple might be a good idea, for example inside a calculation in your library where a user of your API can’t get confused because it’s not part of the external interface.

In my two examples I tried to come up with possible alternatives and generally speaking I don’t think that you need tuples and can find more meaningful ways to express the same thing. But please judge for yourself and come up with code that works for you and the team you’re working in.