Pass-By-Reference in Java

Java is Pass-By-Value. I list some alternatives.

How Values are passed in Java

When you invoke a method in Java you always pass a copy of the value (pass-by-value). If it is of a primitive type (boolean, int, double etc.) then you simply get a copy of the value. But Java also knows reference types. That’s anything that extends Object (String, int[], Integer etc.). Those are references to objects. Java does not know references to variables.

I explain references in more detail in What are References in Java?.

A reference to a variable of reference type would be a reference to a reference. This is sometimes hard to understand and maintain. Java simply doesn’t support pass-by-reference, at least not on a language level.

Pass-By-Reference in C#

A regular method in C# is just like it would be in Java. The parameter(s) are passed by value:

void passByValue(int parameter) { ...

But in C# you can use the ref keyword:

void passByRef(ref int parameter) { ...

Example

Let’s say you would like to implement this method:

void toUpperCase(String string);

Here’s a naive implementation:

void toUpperCase(String string) {
  char[] cs = string.toCharArray();
  for (int i = 0; i < cs.length; i++)
    cs[i] -= 32;
  string = String.valueOf(cs);
}

There are two different variables, both named “string”. The one inside toUpperCase does not affect the other variable. And there is no way in Java to make it influence any variables from the caller.

Alternative 1: Return the Value

In this example the solution is very simple: Just return the string:

String toUpperCase(String string) {
  char[] cs = string.toCharArray();
  for (int i = 0; i < cs.length; i++)
    cs[i] -= 32;
  return String.valueOf(cs);
}

In Java you can only return one value. In some cases you want to have multiple values that are returned. In that case you can just define a class for that or use tuples.

Alternative 2: AtomicReference

If you really need a reference then just use an actual reference. The type java.lang.ref.Reference is abstract and should be used for something else. But you can use AtomicReference.

void  toUpperCase(AtomicReference<String> ref) {
  char[] cs = ref.get().toCharArray();
  for (int i = 0; i < cs.length; i++)
    cs[i] -= 32;
  ref.set(String.valueOf(cs));
}

This a bit cumbersome, but works fine in some situations. AtomicReference is thread-safe. However, in this example other threads could alter the value at the same time. Here’s the thread-safe solution:

void  toUpperCase(AtomicReference<String> ref) {
  ref.updateAndGet(s -> {
    char[] cs = s.toCharArray();
    for (int i = 0; i < cs.length; i++)
      cs[i] -= 32;
    return String.valueOf(cs);
  });
}

Alternative 3: Mutable Type

void toUpperCase(StringBuilder builder) {
    for (int i = 0; i < builder.length(); i++)
      builder.setCharAt(i, (char) (builder.charAt(i) - 32));
}


It’s a different type, but this might actually be faster. String operations are often faster when using StringBuilder.
For Integers you can use an AtomicInteger or just create a mutable type yourself. Simply create a class with just one mutable field.

Alternative 4: Consumer (Lambda)

Instead of using references you can just pass the logic for all the values into the method.

void toUpperCase(String string, Consumer out) {
  char[] cs = string.toCharArray();
  for (int i = 0; i < cs.length; i++)
    cs[i] -= 32;
  out.accept(String.valueOf(cs));
}

This only works with Java 8 and newer versions. In older versions you could use an anonymous class.
You can use as many consumers as you need for a method and some methods might even use one consumers more than once.
However, you can’t actually assign the new value to a local variable inside the lambda. In most cases you don’t need that. But you can add the value to a collection or pass it to another method (in this case it’s println).

Alternative 5: Singleton Array

The idea is to use a singleton data structure (also known as a unit set) such as an array of length 1. It’s worst practice. Don’t do that. Arrays are not made for that. The same goes for other data structures, such as collections or mutable tuples. It is ok to use a mutable object (see above) but not some data structure that is intended for something else.

void toUpperCase(String[] string) {
  char[] cs = string[0].toCharArray();
  for (int i = 0; i < cs.length; i++)
    cs[i] -= 32;
  string[0] = String.valueOf(cs);
}

This is just ugly and it’s not clear what’s going on.

Alternative 6: Static Variables

I won’t even go there. Just don’t! That’s even worse than the singleton array.

3 thoughts on “Pass-By-Reference in Java”

Leave a Reply

Your email address will not be published. Required fields are marked *