I want to return two objects from a Java method and was wondering what could be a good way of doing so?
The possible ways I can think of are: return a HashMap<
I almost always end up defining n-Tuple classes when I code in Java. For instance:
public class Tuple2<T1,T2> {
private T1 f1;
private T2 f2;
public Tuple2(T1 f1, T2 f2) {
this.f1 = f1; this.f2 = f2;
}
public T1 getF1() {return f1;}
public T2 getF2() {return f2;}
}
I know it's a bit ugly, but it works, and you just have to define your tuple types once. Tuples are something Java really lacks.
EDIT: David Hanak's example is more elegant, as it avoids defining getters and still keeps the object immutable.
Regarding the issue about multiple return values in general I usually use a small helper class that wraps a single return value and is passed as parameter to the method:
public class ReturnParameter<T> {
private T value;
public ReturnParameter() { this.value = null; }
public ReturnParameter(T initialValue) { this.value = initialValue; }
public void set(T value) { this.value = value; }
public T get() { return this.value; }
}
(for primitive datatypes I use minor variations to directly store the value)
A method that wants to return multiple values would then be declared as follows:
public void methodThatReturnsTwoValues(ReturnParameter<ClassA> nameForFirstValueToReturn, ReturnParameter<ClassB> nameForSecondValueToReturn) {
//...
nameForFirstValueToReturn.set("...");
nameForSecondValueToReturn.set("...");
//...
}
Maybe the major drawback is that the caller has to prepare the return objects in advance in case he wants to use them (and the method should check for null pointers)
ReturnParameter<ClassA> nameForFirstValue = new ReturnParameter<ClassA>();
ReturnParameter<ClassB> nameForSecondValue = new ReturnParameter<ClassB>();
methodThatReturnsTwoValues(nameForFirstValue, nameForSecondValue);
Advantages (in comparison to other solutions proposed):
In the event the method you're calling is private, or called from one location, try
return new Object[]{value1, value2};
The caller looks like:
Object[] temp=myMethod(parameters);
Type1 value1=(Type1)temp[0]; //For code clarity: temp[0] is not descriptive
Type2 value2=(Type2)temp[1];
The Pair example by David Hanak has no syntactic benefit, and is limited to two values.
return new Pair<Type1,Type2>(value1, value2);
And the caller looks like:
Pair<Type1, Type2> temp=myMethod(parameters);
Type1 value1=temp.a; //For code clarity: temp.a is not descriptive
Type2 value2=temp.b;
You can utilize a HashMap<String, Object>
as follows
public HashMap<String, Object> yourMethod()
{
.... different logic here
HashMap<String, Object> returnHashMap = new HashMap<String, Object>();
returnHashMap.put("objectA", objectAValue);
returnHashMap.put("myString", myStringValue);
returnHashMap.put("myBoolean", myBooleanValue);
return returnHashMap;
}
Then when calling the method in a different scope, you can cast each object back to its initial type:
// call the method
HashMap<String, Object> resultMap = yourMethod();
// fetch the results and cast them
ObjectA objectA = (ObjectA) resultMap.get("objectA");
String myString = (String) resultMap.get("myString");
Boolean myBoolean = (Boolean) resultMap.get("myBoolean");
I have a been using a very basic approach to deal with problems of multiple returns. It serves the purpose, and avoids complexity.
I call it the string separator Approach
And it is effective as it can even return values of Multiple Types e.g. int,double,char,string etc
In this approach we make a use of a string that is very unlikely to occur generally. We call it as a separator. This separator would be used to separate various values when used in a function
For example we will have our final return as (for example) intValue separator doubleValue separator... And Then using this string we will retrieve all the information required, that can be of diffrent types as well
Following code will Show the working of this concept
The separator used is !@# and 3 values are being returned intVal,doubleVal and stringVal
public class TestMultipleReturns {
public static String multipleVals() {
String result = "";
String separator = "!@#";
int intVal = 5;
// Code to process intVal
double doubleVal = 3.14;
// Code to process doubleVal
String stringVal = "hello";
// Code to process Int intVal
result = intVal + separator + doubleVal + separator + stringVal + separator;
return (result);
}
public static void main(String[] args) {
String res = multipleVals();
int intVal = Integer.parseInt(res.split("!@#")[0]);
// Code to process intVal
double doubleVal = Double.parseDouble(res.split("!@#")[1]);
// Code to process doubleVal
String stringVal = res.split("!@#")[2];
System.out.println(intVal+"\n"+doubleVal+"\n"+stringVal);
}
}
OUTPUT
5
3.14
hello
BUILD SUCCESSFUL (total time: 2 seconds)
If you want to return two objects you usually want to return a single object that encapsulates the two objects instead.
You could return a List of NamedObject
objects like this:
public class NamedObject<T> {
public final String name;
public final T object;
public NamedObject(String name, T object) {
this.name = name;
this.object = object;
}
}
Then you can easily return a List<NamedObject<WhateverTypeYouWant>>
.
Also: Why would you want to return a comma-separated list of names instead of a List<String>
? Or better yet, return a Map<String,TheObjectType>
with the keys being the names and the values the objects (unless your objects have specified order, in which case a NavigableMap
might be what you want.