blog

Java: How to return two values from a function (and other stories) (updated!)

Updated: Code examples are now at: https://github.com/techtangents/java-return-values

Don’t do this:

public class Demo1 {
   public static void main(final String[] args) {
       final String[] ret = new String[2];
       foo(ret, "ohai");
       System.out.println("ret[0] = " + ret[0]);
       System.out.println("ret[1] = " + ret[1]);
   }

   public static void foo(final String[] ret, final String input) {
       ret[0] = "oh";
       ret[1] = "no";
   }
}

 

This is slightly better, but the type is too weak. A “String[]” has “n” values, not two.


public class Demo2 {
    public static void main(final String[] args) {
        final String[] ret = foo("ohai");
        System.out.println("ret[0] = " + ret[0]);
        System.out.println("ret[1] = " + ret[1]);
    }

    public static String[] foo(final String input) {
        return new String[] {"oh", "alright"};
    }
}

Oh, yeah, this is the business. Tuples are where it's at. Type is strong - exactly two values are returned. Compiler enforces this.


public class Demo3 {
    public static void main(final String[] args) {
        final Pair<String, String> ret = foo("ohai");
        System.out.println("ret.a = " + ret.a);
        System.out.println("ret.b = " + ret.b);
    }

    public static Pair<String, String> foo(final String input) {
        return Pair.p("oh", "yeah");
    }
}

 

The Pair class looks like this:

public class Pair<A, B> {

    public final A a;
    public final B b;

    protected Pair(final A a, final B b) {
        this.a = a;
        this.b = b;
    }

    public static <A, B> Pair<A, B> p(final A a, final B b) {
        return new Pair<A, B>(a, b);
    }
}

 


Tuples are great general-purpose, but if you use a specific tuple of values all the time, you can always make a special-case structure instead:


public class Demo4 {
    public static class Foo {
        private final String toaster;
        private final String muffin;

        private Foo(final String toaster, final String muffin) {
            this.toaster = toaster;
            this.muffin = muffin;
        }

        public static Foo nuFoo(final String toaster, final String muffin) {
            return new Foo(toaster, muffin);
        }

        public String toaster() {
            return toaster;
        }

        public String muffin() {
            return muffin;
        }
    }

    public static void main(final String[] args) {
        final Foo ret = foo("ohai");
        System.out.println("ret.toaster = " + ret.toaster());
        System.out.println("ret.muffin = " + ret.muffin());
    }

    public static Foo foo(final String input) {
        return Foo.nuFoo("oh", "yeah");
    }
}

Private Constructors

Ok, so why did I use a private constructor with a static “factory” method? So, I can change how I generate a Foo, without changing the call signature. Constructors aren’t the only way to create objects. Examples: – I might want to return a concrete subclass of Foo – I might want to return an anonymous subclass of Foo – I might want to return a Foo that I generate as a result of calling other functions

The static method also lets you perform effects in creating the object (e.g. get a Foo from the network) without there being actual side effects in a constructor (which you should absolutely NEVER do).

It also lets you have multiple “factory” methods, for different combinations of parameters, without chaining constructors, which is clumsy.

So, an example:


public class Demo5 {
    public abstract static class Foo {

        public abstract String toaster();
        public abstract String muffin();

        public static Foo nuFoo(final String toaster, final String muffin) {
            return new Foo() {
                @Override
                public String toaster() {
                    return toaster;
                }

                @Override
                public String muffin() {
                    return muffin;
                }
            };
        }
    }

    public static void main(final String[] args) {
        final Foo ret = foo("ohai");
        System.out.println("ret.toaster = " + ret.toaster());
        System.out.println("ret.muffin = " + ret.muffin());
    }

    public static Foo foo(final String input) {
        return Foo.nuFoo("oh", "yeah");
    }
}

 

Notice how the “foo” and “callFoo” functions didn’t change as a result of this.

 

Leave a Reply

*