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.