Skip to main content

How to return multiple objects from a Java method?



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 (since the two Objects are related) or return an ArrayList of Object objects.





To be more precise, the two objects I want to return are (a) List of objects and (b) comma separated names of the same.





I want to return these two Objects from one method because I dont want to iterate through the list of objects to get the comma separated names (which I can do in the same loop in this method).





Somehow, returning a HashMap does not look a very elegant way of doing so.


Comments

  1. 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.

    ReplyDelete
  2. If you know you are going to return two objects, you can also use a generic pair:

    public class Pair<A,B> {
    public final A a;
    public final B b;

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


    Edit A more fully formed implementation of the above:

    package util;

    public class Pair<A,B> {

    public static <P, Q> Pair<P, Q> makePair(P p, Q q) {
    return new Pair<P, Q>(p, q);
    }

    public final A a;
    public final B b;

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

    @Override
    public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((a == null) ? 0 : a.hashCode());
    result = prime * result + ((b == null) ? 0 : b.hashCode());
    return result;
    }

    @Override
    public boolean equals(Object obj) {
    if (this == obj) {
    return true;
    }
    if (obj == null) {
    return false;
    }
    if (getClass() != obj.getClass()) {
    return false;
    }
    @SuppressWarnings("rawtypes")
    Pair other = (Pair) obj;
    if (a == null) {
    if (other.a != null) {
    return false;
    }
    } else if (!a.equals(other.a)) {
    return false;
    }
    if (b == null) {
    if (other.b != null) {
    return false;
    }
    } else if (!b.equals(other.b)) {
    return false;
    }
    return true;
    }

    public boolean isInstance(Class<?> classA, Class<?> classB) {
    return classA.isInstance(a) && classB.isInstance(b);
    }

    @SuppressWarnings("unchecked")
    public static <P, Q> Pair<P, Q> cast(Pair<?, ?> pair, Class<P> pClass, Class<Q> qClass) {

    if (pair.isInstance(pClass, qClass)) {
    return (Pair<P, Q>) pair;
    }

    throw new ClassCastException();

    }

    }


    Notes, mainly around rustiness with Java & generics:


    both a and b are immutable.
    makePair static method helps you with boiler plate typing, which the diamond operator in Java 7 will make less annoying. There's some work to make this really nice re: generics, but it should be ok-ish now. (c.f. PECS)
    hashcode and equals are generated by eclipse.
    the compile time casting in the cast method is ok, but doesn't seem quite right.
    I'm not sure if the wildcards in isInstance are necessary.
    I've just written this in response to comments, for illustration purposes only.

    ReplyDelete
  3. 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.

    ReplyDelete
  4. Before Java 5, I would kind of agree that the Map solution isn't ideal. It wouldn't give you compile time type checking so can cause issues at runtime. However, with Java 5, we have Generic Types.

    So your method could look like this:

    public Map<String, MyType> doStuff();


    MyType of course being the type of object you are returning.

    Basically I think that returning a Map is the right solution in this case because that's exactly what you want to return - a mapping of a string to an object.

    ReplyDelete
  5. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.


    D. Knuth

    ReplyDelete
  6. Alternatively, in situations where I want to return a number of things from a method I will sometimes use a callback mechanism instead of a container. This works very well in situations where I cannot specify ahead of time just how many objects will be generated.

    With your particular problem, it would look something like this:

    public class ResultsConsumer implements ResultsGenerator.ResultsCallback
    {
    public void handleResult( String name, Object value )
    {
    ...
    }
    }

    public class ResultsGenerator
    {
    public interface ResultsCallback
    {
    void handleResult( String aName, Object aValue );
    }

    public void generateResults( ResultsGenerator.ResultsCallback aCallback )
    {
    Object value = null;
    String name = null;

    ...

    aCallback.handleResult( name, value );
    }
    }

    ReplyDelete
  7. As I see it there are really three choices here and the solution depends on the context. You can choose to implement the construction of the name in the method that produces the list. This is the choice you've chosen, but I don't think it is the best one. You are creating a coupling in the producer method to the consuming method that doesn't need to exist. Other callers may not need the extra information and you would be calculating extra information for these callers.

    Alternatively, you could have the calling method calculate the name. If there is only one caller that needs this information, you can stop there. You have no extra dependencies and while there is a little extra calculation involved, you've avoided making your construction method too specific. This is a good trade-off.

    Lastly, you could have the list itself be responsible for creating the name. This is the route I would go if the calculation needs to be done by more than one caller. I think this puts the responsibility for the creation of the names with the class that is most closely related to the objects themselves.

    In the latter case, my solution would be to create a specialized List class that returns a comma-separated string of the names of objects that it contains. Make the class smart enough that it constructs the name string on the fly as objects are added and removed from it. Then return an instance of this list and call the name generation method as needed. Although it may be almost as efficient (and simpler) to simply delay calculation of the names until the first time the method is called and store it then (lazy loading). If you add/remove an object, you need only remove the calculated value and have it get recalculated on the next call.

    ReplyDelete
  8. All possible solutions will be a kludge (like container objects, your HashMap idea, “multiple return values” as realized via arrays). I recommend regenerating the comma-separated list from the returned List. The code will end up being a lot cleaner.

    ReplyDelete
  9. In C++ (STL) there is a pair class for bundling two objects. In Java Generics a pair class isn't available, although there is some demand for it. You could easily implement it yourself though.

    I agree however with some other answers that if you need to return two or more objects from a method, it would be better to encapsulate them in a class.

    ReplyDelete
  10. Why not create a WhateverFunctionResult object that contains your results, and the logic required to parse these results, iterate over then etc. It seems to me that either:


    These results objects are intimately tied together/related and belong together, or:
    they are unrelated, in which case your function isn't well defined in terms of what it's trying to do (i.e. doing two different things)


    I see this sort of issue crop up again and again. Don't be afraid to create your own container/result classes that contain the data and the associated functionality to handle this. If you simply pass the stuff around in a HashMap or similar, then your clients have to pull this map apart and grok the contents each time they want to use the results.

    ReplyDelete
  11. PASS A HASH INTO THE METHOD AND POPULATE IT......

    public void buildResponse(String data, Map response);

    ReplyDelete
  12. public class MultipleReturnValues {

    public MultipleReturnValues() {
    }

    public static void functionWithSeveralReturnValues(final String[] returnValues) {
    returnValues[0] = "return value 1";
    returnValues[1] = "return value 2";
    }

    public static void main(String[] args) {
    String[] returnValues = new String[2];
    functionWithSeveralReturnValues(returnValues);
    System.out.println("returnValues[0] = " + returnValues[0]);
    System.out.println("returnValues[1] = " + returnValues[1]);
    }

    }

    ReplyDelete

Post a Comment

Popular posts from this blog

[韓日関係] 首相含む大幅な内閣改造の可能性…早ければ来月10日ごろ=韓国

div not scrolling properly with slimScroll plugin

I am using the slimScroll plugin for jQuery by Piotr Rochala Which is a great plugin for nice scrollbars on most browsers but I am stuck because I am using it for a chat box and whenever the user appends new text to the boxit does scroll using the .scrollTop() method however the plugin's scrollbar doesnt scroll with it and when the user wants to look though the chat history it will start scrolling from near the top. I have made a quick demo of my situation http://jsfiddle.net/DY9CT/2/ Does anyone know how to solve this problem?

Why does this javascript based printing cause Safari to refresh the page?

The page I am working on has a javascript function executed to print parts of the page. For some reason, printing in Safari, causes the window to somehow update. I say somehow, because it does not really refresh as in reload the page, but rather it starts the "rendering" of the page from start, i.e. scroll to top, flash animations start from 0, and so forth. The effect is reproduced by this fiddle: http://jsfiddle.net/fYmnB/ Clicking the print button and finishing or cancelling a print in Safari causes the screen to "go white" for a sec, which in my real website manifests itself as something "like" a reload. While running print button with, let's say, Firefox, just opens and closes the print dialogue without affecting the fiddle page in any way. Is there something with my way of calling the browsers print method that causes this, or how can it be explained - and preferably, avoided? P.S.: On my real site the same occurs with Chrome. In the ex