Tuples in Java

28 April 2006

Bart Schuller

by Bart Schuller

Every once in a while, a java programmer wonders how do I return multiple values from my method? Perl and lisp can return lists, but java is constrained to return just one object. Here’s how that limitation can be overcome. Note that this requires a Java 5 implementation.

Let's start with an example program:


package org.smop.tests;

import java.util.ArrayList;
import java.util.Collection;

import org.smop.generics.Tuple;

public class TupleTest {
        public static Tuple<String, Integer> returnTwo() {
                return new Tuple<String, Integer>("Hello", 5);
        }

        public static Tuple<Collection<String>, Tuple<String, String>> returnComplex() {
                Collection<String> l = new ArrayList<String>();
                l.add("one");
                l.add("two");

                return new Tuple<Collection<String>, Tuple<String, String>>(
                                l,
                                new Tuple<String, String>("c1", "c2"));
        }

        public static void main(String[] args) {
                Tuple<String, Integer> r1 = returnTwo();
                System.err.println(r1.first+" unboxing: "+(r1.second -2));

                Tuple<Collection<String>, Tuple<String, String>> r2 = returnComplex();
                for (String string : r2.first) {
                        System.err.println(string);
                }
                System.err.println(r2.second.first + " " + r2.second.second);
        }
}

When we run this, the output is:


Hello unboxing: 3
one
two
c1 c2

The first method, returnTwo() needs to return a String and an integer. People sometimes resort to returning arrays or HashMaps, but particularly in this case, where the values are not of the same type, this gets ugly.

The solution here is to use a generic type Tuple which in this case has two type parameters. We declare the return value as being a Tuple of String and Integer and return a new object of that type. Notice that we can't use int here, but thanks to the automatic boxing and unboxing, the type Integer acts just like plain int.

The second method combines two tuples so it can return three different types. As you can see, it quickly becomes unreadable.

Here's our Tuple class:


package org.smop.generics;

/**
 * Generic Tuple class, for returning multiple objects.
 * @author Bart Schuller &lt;generics@smop.org&gt;
 *
 * @param <T1> the type of the first object
 * @param <T2> the type of the second object
 */
public class Tuple<T1, T2> {
        public T1 first;
        public T2 second;

        public Tuple(T1 first, T2 second) {
                this.first = first;
                this.second = second;
        }
}

Notice that it is extremely simple. I'll leave the implementation of a Tuple3 class as an excercise for the reader...