Tuesday, October 9, 2012

Return Multiple Values from a Function with Java Generics

Ever wanted to return multiple values, objects from a function call. Unfortunately, the return statement allows us to specify only a single object.

Therefore, what could be the solution. One solution is that we create an Object array and then put the objects that we want to return inside that array and specify the array in the return statement. A better solution would be to create a special class for every scenario we encounter. But, this methodology is also fraught with problems as the number of special cases increase in a large project, the number of "just only" special classes will also increase.

Fortunately, java generics is there to rescue us and give us a simple, effective and niche solution to this problem. With generics, you'll be able to address the problem once and give an universal solution; thus reusing our solution whenever it is needed in the future.

I came across this concept while I was reading about Generics in Thinking In Java by Bruce Eckel. So I had the idea that it is worth sharing. I would recommend this book to every Java enthusiast.

Without much ado, let us see how to implement this.

This concept is called a tuple, and it is simply a group of objects wrapped together into a single object. The recipient of the object is allowed to read the elements but not put new ones in. (This concept is also called a Data Transfer Object (or Messenger.)

As we'll see, we can easily extend the classes to create our own tuples (of any length; although there is a caveat. Refer to the end note.)

For example, I have a requirement that I have to return two objects from a function call. To do this, I would create the following class first:

 package tuplelibrary;  
 /**  
  *  
  * @param <A>  
  * @param <B>  
  */  
 public class TwoTuple<A, B> {  
     public final A first;  
     public final B second;  
     /**  
      *   
      * @param a  
      * @param b  
      */  
     public TwoTuple(A a, B b) {  
         first = a;  
         second = b;  
     }  
     @Override  
     public String toString(){  
         return "(" + first + ", " + second + ")";   
     }  
 }  

The constructor takes the objects to be saved/stored in the Tuple. Notice the generic parameters; they ensure full type safety of your objects and the tuple also implicitly maintains the ordering of your objects that you have inserted.

Now, let us see how to use this code.

 public <A, B> TwoTuple<List<Integer>, String> test(List<integer> list, String str) {  
         return new TwoTuple<List<Integer>, String>(list, str);  
     }  

Now, if we want to extend this library, and let's say that we want to return three objects from our function call, then we just have to create a new class and inherit from the existing TwoTuple class.

 package tuplelibrary;  
 /**  
  * @param <A>  
  * @param <B>  
  * @param <C>  
  */  
 public class ThreeTuple<A, B, C> extends TwoTuple<A, B> {  
     public final C third;  
     /**  
      *   
      * @param a  
      * @param b  
      * @param c  
      */  
     public ThreeTuple(A a, B b, C c) {  
         super(a, b);  
         third = c;  
     }  
     @Override  
     public String toString() {  
         return "(" + first + ", " + second + ", " + third + ")";  
     }  
 }  

In order to use ThreeTuple, we would write the same return statement again with a small change, ofcourse:

 return new ThreeTuple<List<Integer>, String, Integer>(list, str, i);  

Thus, we saw how to create a small library of our own using Generics to return multiple objects from any function call.

Note: The tuple library can very easily be misunderstood. If you're returning more than three objects from your function call, then I would suggest that instead of using or extending this library, you should probably revisit your business logic.

Thank You and Happy Coding.

7 comments:

  1. Or you can just use javatuples library (http://www.javatuples.org/)

    ReplyDelete
    Replies
    1. Thank you Gregor for sharing that knowledge.. wasn't aware of that.

      Delete
  2. Thanks Bhaskar, Indeed cool tip. worth including in my list of Generics Interview Questions

    ReplyDelete
  3. I would agree with this as an excellent approach. I have suggested it before in other languages:
    http://nerds-central.blogspot.co.uk/2010/01/using-tuples-to-synthesis-polyadic.html

    However, I have had a lot of push back from other team members who find the tuple based code hard to understand. No - I don't see why either!

    ReplyDelete
  4. My opinion is that if you need a function which returns multiple objects, you probably have a design flaw. You are most certainly breaking the S in SOLID (single responsability principle). After considering other better options, if you still feel this is what you need, don't use generics. Create a real concrete business object aggregating both objects and voilà!

    ReplyDelete
    Replies
    1. I agree with your opinion Philippe and that is why I mentioned the same in the end note.
      But if I still have to return multiple objects, then why not do it in a generic fashion which can be reused again and again, instead of creating concrete business objects for every scenario (which can prove cumbersome and detrimental in a big project).

      At the end the generic solution is also aggregating n number of objects before returning.

      Delete
  5. I agree with Philippe. Tuples can easily make more harm than usefulness. I admit I have similar class in my project too and sometimes I use it, however I find usage of tuples is sign of my laziness, and I never clutter a public API with them.

    They were reasonably rejected in Guava project,
    http://code.google.com/p/guava-libraries/wiki/IdeaGraveyard#Tuples_for_n_%3E=_2 see also link to interesting SO discussion.

    I wouldn't also implement ThreeTuple as child of TwoTuple, I would use composition instead.

    ReplyDelete