Tutorial :Should Java method arguments be used to return multiple values?



Question:

Since arguments sent to a method in Java point to the original data structures in the caller method, did its designers intend for them to used for returning multiple values, as is the norm in other languages like C ?

Or is this a hazardous misuse of Java's general property that variables are pointers ?


Solution:1

A long time ago I had a conversation with Ken Arnold (one time member of the Java team), this would have been at the first Java One conference probably, so 1996. He said that they were thinking of adding multiple return values so you could write something like:

x, y = foo();  

The recommended way of doing it back then, and now, is to make a class that has multiple data members and return that instead.

Based on that, and other comments made by people who worked on Java, I would say the intent is/was that you return an instance of a class rather than modify the arguments that were passed in.

This is common practice (as is the desire by C programmers to modify the arguments... eventually they see the Java way of doing it usually. Just think of it as returning a struct. :-)

(Edit based on the following comment)

I am reading a file and generating two arrays, of type String and int from it, picking one element for both from each line. I want to return both of them to any function which calls it which a file to split this way.

I think, if I am understanding you correctly, tht I would probably do soemthing like this:

// could go with the Pair idea from another post, but I personally don't like that way  class Line  {      // would use appropriate names      private final int intVal;      private final String stringVal;        public Line(final int iVal, final String sVal)      {          intVal    = iVal;          stringVal = sVal;      }        public int getIntVal()      {          return (intVal);      }        public String getStringVal()      {          return (stringVal);      }        // equals/hashCode/etc... as appropriate  }  

and then have your method like this:

public void foo(final File file, final List<Line> lines)  {      // add to the List.  }  

and then call it like this:

{      final List<Line> lines;        lines = new ArrayList<Line>();      foo(file, lines);  }  


Solution:2

In my opinion, if we're talking about a public method, you should create a separate class representing a return value. When you have a separate class:

  • it serves as an abstraction (i.e. a Point class instead of array of two longs)
  • each field has a name
  • can be made immutable
  • makes evolution of API much easier (i.e. what about returning 3 instead of 2 values, changing type of some field etc.)

I would always opt for returning a new instance, instead of actually modifying a value passed in. It seems much clearer to me and favors immutability.

On the other hand, if it is an internal method, I guess any of the following might be used:

  • an array (new Object[] { "str", longValue })
  • a list (Arrays.asList(...) returns immutable list)
  • pair/tuple class, such as this
  • static inner class, with public fields

Still, I would prefer the last option, equipped with a suitable constructor. That is especially true if you find yourself returning the same tuple from more than one place.


Solution:3

I do wish there was a Pair<E,F> class in JDK, mostly for this reason. There is Map<K,V>.Entry, but creating an instance was always a big pain.

Now I use com.google.common.collect.Maps.immutableEntry when I need a Pair


Solution:4

See this RFE launched back in 1999:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4222792

I don't think the intention was to ever allow it in the Java language, if you need to return multiple values you need to encapsulate them in an object.

Using languages like Scala however you can return tuples, see:

http://www.artima.com/scalazine/articles/steps.html

You can also use Generics in Java to return a pair of objects, but that's about it AFAIK.

EDIT: Tuples

Just to add some more on this. I've previously implemented a Pair in projects because of the lack within the JDK. Link to my implementation is here:

http://pbin.oogly.co.uk/listings/viewlistingdetail/5003504425055b47d857490ff73ab9

Note, there isn't a hashcode or equals on this, which should probably be added.

I also came across this whilst doing some research into this questions which provides tuple functionality:

http://javatuple.com/

It allows you to create Pair including other types of tuples.


Solution:5

You cannot truly return multiple values, but you can pass objects into a method and have the method mutate those values. That is perfectly legal. Note that you cannot pass an object in and have the object itself become a different object. That is:

private void myFunc(Object a) {      a = new Object();  }  

will result in temporarily and locally changing the value of a, but this will not change the value of the caller, for example, from:

Object test = new Object();  myFunc(test);  

After myFunc returns, you will have the old Object and not the new one.

Legal (and often discouraged) is something like this:

private void changeDate(final Date date) {      date.setTime(1234567890L);  }  

I picked Date for a reason. This is a class that people widely agree should never have been mutable. The the method above will change the internal value of any Date object that you pass to it. This kind of code is legal when it is very clear that the method will mutate or configure or modify what is being passed in.

NOTE: Generally, it's said that a method should do one these things:

  • Return void and mutate its incoming objects (like Collections.sort()), or
  • Return some computation and don't mutate incoming objects at all (like Collections.min()), or
  • Return a "view" of the incoming object but do not modify the incoming object (like Collections.checkedList() or Collections.singleton())
  • Mutate one incoming object and return it (Collections doesn't have an example, but StringBuilder.append() is a good example).

Methods that mutate incoming objects and return a separate return value are often doing too many things.


Solution:6

There are certainly methods that modify an object passed in as a parameter (see java.io.Reader.read(byte[] buffer) as an example, but I have not seen parameters used as an alternative for a return value, especially with multiple parameters. It may technically work, but it is nonstandard.


Solution:7

It's not generally considered terribly good practice, but there are very occasional cases in the JDK where this is done. Look at the 'biasRet' parameter of View.getNextVisualPositionFrom() and related methods, for example: it's actually a one-dimensional array that gets filled with an "extra return value".

So why do this? Well, just to save you having to create an extra class definition for the "occasional extra return value". It's messy, inelegant, bad design, non-object-oriented, blah blah. And we've all done it from time to time...


Solution:8

Generally what Eddie said, but I'd add one more:

  • Mutate one of the incoming objects, and return a status code. This should generally only be used for arguments that are explicitly buffers, like Reader.read(char[] cbuf).


Solution:9

I had a Result object that cascades through a series of validating void methods as a method parameter. Each of these validating void methods would mutate the result parameter object to add the result of the validation.

But this is impossible to test because now I cannot stub the void method to return a stub value for the validation in the Result object.

So, from a testing perspective it appears that one should favor returning a object instead of mutating a method parameter.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »