views:

1151

answers:

10

Suppose I have this in C++:

void test(int &i, int &j)
{
    ++i;
    ++j;
}

The values are altered inside the function and then used outside. How could I write a code that does the same in Java? I imagine I could return a class that encapsulates both values, but that seems really cumbersome.

+9  A: 

Java has no equivalent of C++ references. The only way to get this to work is to encapsulate the values in another class and swap the values within the class.

Here is a lengthy discussion on the issue: http://www.yoda.arachsys.com/java/passing.html

JaredPar
+6  A: 

Well, there are a couple of workarounds. You mentioned one yourself. Another one would be:

public void test(int[] values) {
    ++values[0];
    ++values[1];
}

I would go with the custom object, though. It’s a much cleaner way. Also, try to re-arrange your problem so that a single method doesn’t need to return two values.

Bombe
+5  A: 

Java does not have pass-by-reference. You must encapsulate to achieve the desired functionality. Jon Skeet has a brief explanation why pass-by-reference was excluded from Java.

Jason
A: 

You could construct boxed objects, ie,

Integer iObj = new Integer(i);
Integer jObj = new Integer(j);

and write your routine as

public void test(Integer i, Integer j){
  i = i.add(1);
  j = j.add(1);
}

For any number of reasons, the designers of Java felt call-by-value was better; they purposefully didn't include a method for call by reference. (Strictly, they pass copies of references to the objects, with the special case for the primitive types that they are purely call by value. But the effect is the same.)

Charlie Martin
That will still not change the objects outside of the method, as Integers are immutable.
Bombe
Where did you get the idea that Integer had an add() method? Anyway, as Bombe pointed out, Integers are immutable, which leaves you with the exact same problem (but with more typing).
Alan Moore
Looks like I should have addressed that comment to jinguy; he's the one who added those methods.
Alan Moore
you could pass in AtomicInteger instead, that's mutable. That isn't its intended purpose, but would almost make this method work.
John Gardner
this won't work as object references are passed by value, as everything in java. read this. http://stackoverflow.com/questions/373419/whats-the-difference-between-a-parameter-passed-by-reference-vs-passed-by-value#373429
Johannes Schaub - litb
it has nothing todo with whether or not Integer is immutable tho. .. ugg it was jinguy who added those code in test. well ok it *had* something todo with immutability before jinguy changed that answer :p now it solely has todo with pass-by-value instead of pass-by-reference :)
Johannes Schaub - litb
A: 

You have to box it (your way) somehow.

Integer is immutable. so useless. int is mutable but since java is pass by value then its unusable again in that case. See these pages for more explanations: Java is Pass-by-Value, Dammit! and int vs Integer

Apache commons lang has a MutableInt class. Or you could write it yourself.

In any case, it should not be that bad because it should not happen often. If it does, then you should definitively change the way you code in Java.

Loki
+1  A: 

Simulating reference with wrappers.

One way you can have this behavior somehow simulated is create a generic wrapper.

public class _<E> {
    E ref;
    public _( E e ){
        ref = e;
    }
    public E g() { return ref; }
    public void s( E e ){ this.ref = e; }

    public String toString() {
        return ref.toString();
    }
}

I'm not too convinced about the value of this code, by I couldn't help it, I had to code it :)

So here it is.

The sample usage:

public class Test {

    public static void main ( String [] args ) {
        _<Integer> iByRef = new _<Integer>( 1 );
        addOne( iByRef );
        System.out.println( iByRef ); // prints 2

        _<String> sByRef = new _<String>( "Hola" );
        reverse( sByRef ); 
        System.out.println( sByRef ); // prints aloH

    }

    // Change the value of ref by adding 1
    public static void addOne( _<Integer> ref ) { 
        int i = ref.g();
        ref.s( ++i  );

        // or 
        //int i = ref.g();
        //ref.s( i + 1 );

    }
    // Reverse the vale of a string.
    public static void reverse( _<String> otherRef ) { 
        String v = otherRef.g();
        String reversed = new StringBuilder( v ).reverse().toString();
        otherRef.s( reversed );
    }

}

The amusing thing here, is the generic wrapper class name is "_" which is a valid class identifier. So a declaration reads:

For an integer:

_<Integer> iByRef = new _<Integer>( 1 );

For a String:

_<String> sByRef = new _<String>( "Hola" );

For any other class

_<Employee> employee = new _<Employee>( Employee.byId(123) );

The methods "s" and "g" stands for set and get :P

OscarRyz
+4  A: 

A better question: why are you creating methods with such side-effects?

Generally, this is a strong indication that you should extract the data into a separate class, with public accessors that describe why the operation is taking place.

kdgregory
A: 

Are the two integers related? Like a pair of x/y coordinates? If so, I would put the integers in a new class and pass that class into the method.

class A{ 
  public void test(Coord c)
  {
    c.x++;
    c.y++;
  }
  private class Coord{
    public int x, y;
  }
}

If the two integers are not related, you might want to think about why you are passing them into the same method in the first place.

Michael Angstadt
A: 

Though its a bad design pattern IMHO, Another possible solution is

static void test(AtomicInteger i, AtomicInteger j)
{
    i.incrementAndGet();
    j.incrementAndGet();
}
Peter Lawrey
A: 

@Eric M:

Passing references to a function for the purpose of receiving [out] data is evil because the syntax of the code at the calling site does not indicate (to the programmer) that the object being passed into the function may be modified across the function call.

void foo(int& bar);

int n = 42;    
foo(n);      // No syntactic hint that 'n' may be modified by this call!

In this example, it is not at all obvious that foo() can modify the value of the local variable 'n' unless you examine the prototype and/or implementation of foo(). This makes it more difficult to understand what this code is doing.

If foo() is not intended to modify the parameter, it should be a const reference: void foo(const int& bar); if it does modify the parameter, the caller should be required to use pointer notation in order to emphasize this possible side-effect at the call site: void foo(int *bar);

This is not just a matter of coding style, but can have an impact on the efficiency of the code generated. If you pass an object by non-const reference, the compiler MUST assume that the object has been modified in the call and must reload any cached data that was previously loaded from that object. Although programmers should not waste mental energy fussing over the efficiency of every line of code, we also should not employ constructs that unnecessarily prevent the compiler from performing whatever optimizations it can.

Aside from syntactic convenience, the other "advantage" of references is that the compiler will go to great lengths to ensure that a reference does not contain a NULL pointer. So one might argue that using a reference means that foo() does not need to check for a NULL pointer. However, it is still possible for the caller to attempt to pass a NULL object to this function, which will cause an exception:

   int *bar = NULL;
   foo(*bar);   // This will throw an exception at runtime!

So instead of locally handling the possibility of a NULL object pointer and encapsulating any error handling, use of reference parameters simply pushes this problem out onto the caller.

In short, there is never a good reason to pass any parameter to a function by non-const reference; this can always be replaced by either a const reference or a pointer.

Chrispy
I hate this kind of black/white advice. There are many good uses for non-const reference parameters, and if your function name is well thought-out, it should be enough of a hint that the parameter is an out-parameter. Having said that, I do like C#'s requirement of the keywords 'ref' or 'out' for these types of parameters. Java's lack of pass-by-reference is a major handicap.
Yuyo