Tuples in Java

Java doesn’t provide tuples. Here are some ideas what you can do about it.

Different Types of Tuples

There are very different situations where you need tuples. Two-tuples (pairs) are probably the most commonly used tuples and Java already has Map.Entry. However, you must know exactly what kind of tuples you need. Here are some properties of tuples:

  • mutable / immutable
  • number of fields
  • named fields / enumerated fields / both
  • serializable, cloneable, compareable etc.
  • tuple with special methods

There can’t be a general implementation of tuples because they can be so different. Can you change the sate of a tuple? Can you compare a pair to a triplet? This depends on how they will be used.

Arrays are not Tuples!

Since Java doesn’t provide tuples it’s often tempting to just use arrays. But they are always mutable and there’s no guarantee that all threads see the same content. So they are not suitable for parallel programming.

Existing Tuples

If you simply need a pair you could just use java.util.Map.Entry<K, V>, but you’d still have to implement that interface unless you just use or extend AbstractMap.SimpleEntry. A 1-tuple exists as java.util.concurrent.atomic.AtomicReference. And then there is java.util.Optional, which may or may not contain one value.

For a full set of implementations you can use a library such as:
http://www.javatuples.org/

Custom Types

In many cases this is the best option. Simply create a class or an interface for the type you need. You have full control what kind of mutations (if any) are allowed and you have meaningful names for the type and the fields. Tools can generate methods such as getters, setters, hashCode and equals. Then you can simply add any methods to that type and you do not need a utility class full of static methods for your tuples. Your tuples can be observable, comparable, serializeable etc.

Maps

A java.util.Map is somewhat similar to a tuple. But you need to define the fields. For that you can use an enum and then use an EnumMap as the Map-implementation.

A Calendar works like that. It’s really a 17-tuple, with fields such as ERA, YEARHOUR_OF_DAY, etc. This exists since JDK1.1, before enums where added to Java. So instead of enum constants they used static int fields and Calendar doesn’t actually implement Map<Integer, Integer>. The newer type java.time.LocalDateTime (since Java 8) uses TemporalField, which is implemented by the enum ChronoField. So this maps TemporalField to int.

Consumers

In some cases you can use a functional interface instead of a tuple. A method could return a BiConsumer instead of a Pair. If more values are needed a functional interface needs to be defined. The parameters of the consumer can have meaningful names. Another benefit is that it can be lazy (values are calculated on access only), but you need to handle the possibility that it gets called multiple times.

Leave a Reply

Your email address will not be published. Required fields are marked *