Java pass by reference and pass by value

Introduction:

There are two ways of passing arguments in Java, pass by value and pass by reference.

Pass by value-this means passing a copy of the value to a method. Applies to primitive types such as int, byte,char,long,float.If the value is changed downstream in the method it is passed to, the original value remains unchanged.

Pass by reference-Java uses this mechanism to pass memory location references of objects rather than the values the objects hold. This applies to non -primitive data types. If the value of the object is changed downstream from the method its passed to, the original value is changed as well.

Demonstration of pass by value by use of example.

We are going to learn difference between pass by value and pass by reference using the program below.

The program has a main method and two methods:  public void processTaskOne(String param1, String param2, int val) and private void processSubTaskOne(String param, int val, boolean exceptionOccured).

From the main method,processTaskOne is passed two parameters param1 a String,param2 a String and val an int that represents a random integer between 1 and 99.The param1 and param2 will just be logged on the console along the val value.They are hypothetical parameters that could be used in other processing logic.In this method,we also have a variable exceptionOccured initialized to false.Its use is to check whether an exception occurred in the helper method processSubTaskOne.Before calling the method processSubTaskOne,the value of exceptionOccured is printed on the console.The method processSubTaskOne receives param of type String which could be either param1 or param2 fed into processTaskOne(in this case param has no business function),val of type int which is the random value between 1 and 99 and the variable exceptionOccured.If the val value is between 1 and 50,it is considered in the normal range and a string starting with ‘Normal processing for param:’ is printed on the console.exceptionOccured value is also unchanged and control returns to the calling method  processTaskOne whereby the value of exceptionOccured is printed on the console in the string starting with ‘After subtask execution(exceptionOccured)=’.If the value is between 51 to 99,an exception is thrown,and handled in the catch block.In the catch block,an error log starting with the string  ‘Error occured in subtask with’ is printed on the console.The value of exceptionOccured is also set to true and control returns to the calling method processTaskOne.Once control returns, the value of exceptionOccured is printed on the console.A condition evaluation on the variable exceptionOccured is done and if an exeption occurred,i.e  if exceptionOccured is true,the string‘There was an error processing subtask’ is printed else the string ‘Processed subtask successfully.’ is printed.

The outcome:

Lets see and interrogate and explain the outcomes of the execution of the program in the  following examples.

Example 1-Pass by value

 

package devsought;

 

import java.util.concurrent.ThreadLocalRandom;

 

 

public class JavaPassByValueExample1 {

 

    public static void main(String... args) {

        int random = ThreadLocalRandom.current().nextInt(1, 100);

        System.out.println(random);

        JavaPassByValueExample1 byValueExample1 = new JavaPassByValueExample1();

        byValueExample1.processTaskOne("Param1Value", "Param2Value", random);

 

    }

 

    public void processTaskOne(String param1, String param2, int val) {

        //print out parameters

        System.out.println("Param1:" + param1 + ", Param2:" + param2 + ", Value:" + val);

        //simulate some work

        boolean exceptionOccured = false;

        System.out.println("Before subtask execution(exceptionOccured)=" + exceptionOccured);

        processSubTaskOne(param2, val, exceptionOccured);

        System.out.println("After subtask execution(exceptionOccured)=" + exceptionOccured);

        if (exceptionOccured) {

            System.err.println("There was an error processing subtask");

        } else {

            System.out.println("Processed subtask successfully.");

        }

 

    }

 

    private void processSubTaskOne(String param, int val, boolean exceptionOccured) {

        try {

            if (val > 50) {

                //throw exception

                throw new Exception("Subtask One val out of range:" + val);

            } else {

                //normal value range processing

                System.out.println("Normal processing for param:" + param + " value " + val);

            }

        } catch (Exception ex) {

            System.err.println("Error occured in subtask with param " + param + " of value " + val + ", Error message:" + ex.getMessage());

            exceptionOccured = true;

        }

 

    }

}

Output on run 1 with val in the range 1 to 50:

22

Param1:Param1Value, Param2:Param2Value, Value:22

Before subtask execution(exceptionOccured)=false

Normal processing for param:Param2Value value 22

After subtask execution(exceptionOccured)=false

Processed subtask successfully.

BUILD SUCCESSFUL (total time: 0 seconds)

 

Output on run 2 with val in the range 51 to 99:

53

Param1:Param1Value, Param2:Param2Value, Value:53

Before subtask execution(exceptionOccured)=false

Error occured in subtask with param Param2Value of value 53, Error message:Subtask One val out of range:53

After subtask execution(exceptionOccured)=false

Processed subtask successfully.

BUILD SUCCESSFUL (total time: 0 seconds)

Explanation:

When the value of val is in the range 1-50,there is normal processing and the value of exceptionOccured is unchanged.However,when val is in the range 51-99 an exception occurs and the error message as in our run 2 above,’ Error occured in subtask with param Param2Value of value 53, Error message:Subtask One val out of range:53’ is printed.The variable exceptionOccured is set to true.When control returns to processTaskOne method,we expect the line ‘After subtask execution(exceptionOccured)=true’ to be printed as well as the line ‘There was an error processing subtask’ to be printed.To the contrary ,’After subtask execution(exceptionOccured)=false’ and ‘Processed subtask successfully.’ is printed.This is because in the call to processSubTaskOne(param2, val, exceptionOccured),the variable exceptionOccured was passed by value and even if the passed value was modified downstream,the original value would remain unchanged and we do not get the results we expected.This is because exceptionOccured is a boolean and a boolean is a primitive data type.

We want to maintain our design of the program ,but how do we solve this challenge?Answer:We modify our program to use pass by reference.

How to pass primitives using pass by reference

We can achieve the primitive type in an array as an argument this by one of the below three methods.

  1. Pass the primitive type in an array as an argument.
  2. Making the primitive variable a member variable inside the class and passing the Class instance to the method that needs to modify it.
  3. Return an updated value from the helper method and update the local variable in the class or in the calling method.

Example 2-Passing a primitive in an array as an argument

In this approach,we modify our program and declare a boolean array to hold our exceptionOccured variable.We then pass in the array as an argument to the processSubTaskOne method.When an exception occurs,we update the element in the array whose index is our exceptionOccured variable.In this approach,we use array[index] to access our boolean variable and our program works as expected.

Program:

package devsought;

 

import java.util.concurrent.ThreadLocalRandom;

 

public class JavaPassByValueExample2 {

 

    public static void main(String... args) {

        int random = ThreadLocalRandom.current().nextInt(1, 100);

        System.out.println(random);

        JavaPassByValueExample2 byValueExample1 = new JavaPassByValueExample2();

        byValueExample1.processTaskOne("Param1Value", "Param2Value", random);

 

    }

 

    public void processTaskOne(String param1, String param2, int val) {

        //print out parameters

        System.out.println("Param1:" + param1 + ", Param2:" + param2 + ", Value:" + val);

        //simulate some work

        boolean[] exceptionOccured = {false};

        System.out.println("Before subtask execution(exceptionOccured)=" + exceptionOccured[0]);

        processSubTaskOne(param2, val, exceptionOccured);

        System.out.println("After subtask execution(exceptionOccured)=" + exceptionOccured[0]);

        if (exceptionOccured[0]) {

            System.err.println("There was an error processing subtask");

        } else {

            System.out.println("Processed subtask successfully.");

        }

 

    }

 

    private void processSubTaskOne(String param, int val, boolean[] exceptionOccured) {

        try {

            if (val > 50) {

                //throw exception

                throw new Exception("Subtask One val out of range:" + val);

            } else {

                //normal value range processing

                System.out.println("Normal processing for param:" + param + " value " + val);

            }

        } catch (Exception ex) {

            System.err.println("Error occured in subtask with param " + param + " of value " + val + ", Error message:" + ex.getMessage());

            exceptionOccured[0] = true;

        }

 

    }

}

Output on run 1 with val in the range 1 to 50:

7

Param1:Param1Value, Param2:Param2Value, Value:7

Before subtask execution(exceptionOccured)=false

Normal processing for param:Param2Value value 7

After subtask execution(exceptionOccured)=false

Processed subtask successfully.

Output on run 2 with val in the range 51 to 99:

 

91

Param1:Param1Value, Param2:Param2Value, Value:91

Error occured in subtask with param Param2Value of value 91, Error message:Subtask One val out of range:91

Before subtask execution(exceptionOccured)=false

After subtask execution(exceptionOccured)=true

There was an error processing subtask

BUILD SUCCESSFUL (total time: 0 seconds)

Explanation:

In both scenarios,the output is as expected.

Example 3- Making the primitive variable a member variable inside the class  and passing the Class instance  to the  method that needs to modify it

Program:

package devsought;

 

import java.util.concurrent.ThreadLocalRandom;

 

 

public class JavaPassByValueExample3 {

 

    private String param1;

    private String param2;

    private boolean exceptionOccured;

 

    public JavaPassByValueExample3(String param1, String param2, boolean exceptionOccured) {

        this.param1 = param1;

        this.param2 = param2;

        this.exceptionOccured = exceptionOccured;

    }

 

    public static void main(String... args) {

        int random = ThreadLocalRandom.current().nextInt(1, 100);

        System.out.println(random);

        JavaPassByValueExample3 byValueExample1 = new JavaPassByValueExample3("Param1Value", "Param2Value", false);

        byValueExample1.processTaskOne(byValueExample1, random);

 

    }

 

    public void processTaskOne(JavaPassByValueExample3 example3, int val) {

        //print out parameters

        System.out.println("Param1:" + example3.getParam1() + ", Param2:" + example3.getParam2() + ", Value:" + val);

        //simulate some work

       // boolean exceptionOccured = false;

        System.out.println("Before subtask execution(exceptionOccured)="+example3.exceptionOccured);

        processSubTaskOne(example3, val);

        System.out.println("After subtask execution(exceptionOccured)="+example3.exceptionOccured);

        if (example3.exceptionOccured) {

            System.err.println("There was an error processing subtask");

        } else {

            System.out.println("Processed subtask successfully.");

        }

 

    }

 

    private void processSubTaskOne(JavaPassByValueExample3 example3, int val) {

        try {

            if (val > 50) {

                //throw exception

                throw new Exception("Subtsak One val out of range:" + val);

            } else {

                //normal value range processing

                System.out.println("Normal processing for param:" + example3.getParam2() + " value " + val);

            }

        } catch (Exception ex) {

            System.err.println("Error occured in subtask with param " + example3.getParam2() + " of value " + val + ", Error message:" + ex.getMessage());

            example3.exceptionOccured = true;

        }

 

    }

 

    /**

     * @return the param1

     */

    public String getParam1() {

        return param1;

    }

 

    /**

     * @param param1 the param1 to set

     */

    public void setParam1(String param1) {

        this.param1 = param1;

    }

 

    /**

     * @return the param2

     */

    public String getParam2() {

        return param2;

    }

 

    /**

     * @param param2 the param2 to set

     */

    public void setParam2(String param2) {

        this.param2 = param2;

    }

 

    /**

     * @return the exceptionOccured

     */

    public boolean isExceptionOccured() {

        return exceptionOccured;

    }

 

    /**

     * @param exceptionOccured the exceptionOccured to set

     */

    public void setExceptionOccured(boolean exceptionOccured) {

        this.exceptionOccured = exceptionOccured;

    }

}

Output on run 1 with val in the range 1 to 50:

35

Param1:Param1Value, Param2:Param2Value, Value:35

Before subtask execution(exceptionOccured)=false

Normal processing for param:Param2Value value 35

After subtask execution(exceptionOccured)=false

Processed subtask successfully.

 

Output on run 2 with val in the range 51 to 99:

97

Param1:Param1Value, Param2:Param2Value, Value:97

Error occured in subtask with param Param2Value of value 97, Error message:Subtsak One val out of range:97

Before subtask execution(exceptionOccured)=false

There was an error processing subtask

After subtask execution(exceptionOccured)=true

Explanation:

In this case,since the variable belongs to the passed in instance,the pass is by reference.If the value of val belonging to the JavaPassByValueExample3 class instance example3  is modified in the processSubTaskOne method in the catch block,the new  value of exeptionOccured reflects in the instance and we have correct state when control returns to the processTaskOne method and an evaluation is done on example3.exceptionOccured.

Example 4- Return an updated value from the helper method and update the local variable in the class or in the calling method.

Program:

package devsought;

 

import java.util.concurrent.ThreadLocalRandom;

 

public class JavaPassByValueExample4 {

 

    public static void main(String... args) {

        int random = ThreadLocalRandom.current().nextInt(1, 100);

        System.out.println(random);

        JavaPassByValueExample4 byValueExample1 = new JavaPassByValueExample4();

        byValueExample1.processTaskOne("Param1Value", "Param2Value", random);

 

    }

 

    public void processTaskOne(String param1, String param2, int val) {

        //print out parameters

        System.out.println("Param1:" + param1 + ", Param2:" + param2 + ", Value:" + val);

        //simulate some work

        boolean exceptionOccured = false;

        System.out.println("Before subtask execution(exceptionOccured)=" + exceptionOccured);

        exceptionOccured = processSubTaskOne(param2, val);

        System.out.println("After subtask execution(exceptionOccured)=" + exceptionOccured);

        if (exceptionOccured) {

            System.err.println("There was an error processing subtask");

        } else {

            System.out.println("Processed subtask successfully.");

        }

 

    }

 

    private boolean processSubTaskOne(String param, int val) {

 

        try {

            if (val > 50) {

                //throw exception

                throw new Exception("Subtsak One val out of range:" + val);

            } else {

                //normal value range processing

                System.out.println("Normal processing for param:" + param + " value " + val);

                return false;

            }

        } catch (Exception ex) {

            System.err.println("Error occured in subtask with param " + param + " of value " + val + ", Error message:" + ex.getMessage());

        }

        return true;

    }

}

Output on run 1 with val in the range 1 to 50:

29

Param1:Param1Value, Param2:Param2Value, Value:29

Before subtask execution(exceptionOccured)=false

Normal processing for param:Param2Value value 29

After subtask execution(exceptionOccured)=false

Processed subtask successfully.

 

Output on run 2 with val in the range 51 to 99:

 

54

Param1:Param1Value, Param2:Param2Value, Value:54

Error occured in subtask with param Param2Value of value 54, Error message:Subtsak One val out of range:54

Before subtask execution(exceptionOccured)=false

There was an error processing subtask

After subtask execution(exceptionOccured)=true

Explanation:This approach updates the value of a primitive variable.When an exception occurs in the method processSubTaskOne an error log  beginning with the string ‘Error occured in subtask with param’ is printed and a true returned to indicate an exception occurred.If normal processing ,a false is returned to indicate no exception occurred.In both instances,the variable exceptionOccured in method processTaskOne is updated and the intended outcome is achieved.

The programs used in illustrations in these articles can be found on Github

About the Author - John Kyalo Mbindyo(Bsc Computer Science) is a Senior Application Developer currently working at NCBA Bank Group,Nairobi- Kenya.He is passionate about making programming tutorials and sharing his knowledge with other software engineers across the globe. You can learn more about him and follow him on  Github.