I noticed there is no no-custom class, n-length, no-cast, type-safe answers yet to returning multiple values.
Here is my go:
import java.util.Objects;
public final class NTuple<V, T extends NTuple<?, ?>> {
private final V value;
private final T next;
private NTuple(V value, T next) {
this.value = value;
this.next = next;
}
public static <V> NTuple<V, ?> of(V value) {
return new NTuple<>(value, null);
}
public static <V, T extends NTuple<?, ?>> NTuple<V, T> of(V value, T next) {
return new NTuple<>(value, next);
}
public V value() {
return value;
}
public T next() {
return next;
}
public static <V> V unpack0(NTuple<V, ?> tuple) {
return Objects.requireNonNull(tuple, "0").value();
}
public static <V, T extends NTuple<V, ?>> V unpack1(NTuple<?, T> tuple) {
NTuple<?, T> tuple0 = Objects.requireNonNull(tuple, "0");
NTuple<V, ?> tuple1 = Objects.requireNonNull(tuple0.next(), "1");
return tuple1.value();
}
public static <V, T extends NTuple<?, NTuple<V, ?>>> V unpack2(NTuple<?, T> tuple) {
NTuple<?, T> tuple0 = Objects.requireNonNull(tuple, "0");
NTuple<?, NTuple<V, ?>> tuple1 = Objects.requireNonNull(tuple0.next(), "1");
NTuple<V, ?> tuple2 = Objects.requireNonNull(tuple1.next(), "2");
return tuple2.value();
}
}
Sample use:
public static void main(String[] args) {
// pre-java 10 without lombok - use lombok's var or java 10's var if you can
NTuple<String, NTuple<Integer, NTuple<Integer, ?>>> multiple = wordCount("hello world");
String original = NTuple.unpack0(multiple);
Integer wordCount = NTuple.unpack1(multiple);
Integer characterCount = NTuple.unpack2(multiple);
System.out.println(original + ": " + wordCount + " words " + characterCount + " chars");
}
private static NTuple<String, NTuple<Integer, NTuple<Integer, ?>>> wordCount(String s) {
int nWords = s.split(" ").length;
int nChars = s.length();
return NTuple.of(s, NTuple.of(nWords, NTuple.of(nChars)));
}
Pros:
- no-custom container class - no need to write a class just for a return type
- n-length - can handle any number of return values
- no-cast - no need to cast from Object
- type-safe - the types are checked via Java's generics
Cons:
- inefficient for large numbers of return values
- according to my experience with python's multiple return values, this should not happen in practice
- heavy type declarations
- can be alleviated by lombok/Java 10
var