Functions in Java (Pass by Reference and Value)

In case you are learning DSA, you should definitely check out our free A2Z DSA Course with videos and blogs.

Functions are fundamental elements in programming that allow you to perform specific tasks or actions. 

Functions are essential in programming for several reasons:

  1. Modularization of Code:
    Functions help break down large and complex code into manageable, reusable modules.
    Imagine having thousands of lines of code. It’s hard to maintain and understand. Functions allow you to compartmentalize these code segments.
  1. Enhancing Readability:
    Functions make your code more readable, especially for others who may review or collaborate on your code. Descriptive function names clarify their purpose.
  1. Code Reusability: Functions enable you to reuse the same block of code multiple times without duplicating it.

Syntax:

return_type function_name(parameters) {
    // Function body
    // Code to perform a specific task
    // Optionally, return a value of return_type
}

Functions in Java

  • return_type: Similar to C++, this specifies the data type of the value that the method returns (if any). It can be any valid Java data type, including primitive types (e.g., int, double) or reference types (e.g., classes).
  • function_name: This is the name of the method. It should follow Java naming conventions and be descriptive of the method’s purpose.
  • parameters: These are the input values that the method accepts (optional). Multiple parameters can be separated by commas. Each parameter has a data type and a name.
  • Method body: The code within curly braces {} is the method’s body. It contains statements that define what the method does.
  • return: If the method is expected to return a value (specified by return_type), you use the return statement to indicate the value to be returned. This statement is optional in methods with a void return type.
public int add(int a, int b) {
    int sum = a + b;
    return sum;
}

In Java, the public keyword indicates the method’s visibility (access modifier). Java methods can have different access modifiers like public, private, protected, or package-private (default).

Suppose you have a Java program that calculates the area of various geometric shapes, including rectangles and circles, within a single, large main function.

Code Before Using Functions:

Java Code

public class AreaCalculator {
    public static void main(String[] args) {
        double rectangleWidth = 5.0;
        double rectangleHeight = 3.0;
        double rectangleArea = rectangleWidth * rectangleHeight;

        double circleRadius = 2.5;
        double circleArea = 3.14159265359 * circleRadius * circleRadius;

        System.out.println("Area of the rectangle: " + rectangleArea);
        System.out.println("Area of the circle: " + circleArea);

    }
}

Output:

Area of the rectangle: 15.0
Area of the circle: 19.634954084937497

Code Using Functions:

Java Code

public class AreaCalculator {

    public static double calculateRectangleArea(double width, double height) {
        return width * height;
    }


    public static double calculateCircleArea(double radius) {
        return 3.14159265359 * radius * radius;
    }

    public static void main(String[] args) {

        double rectangleWidth = 5.0;
        double rectangleHeight = 3.0;
        double rectangleArea = calculateRectangleArea(rectangleWidth, rectangleHeight);

        double circleRadius = 2.5;
        double circleArea = calculateCircleArea(circleRadius);

        System.out.println("Area of the rectangle: " + rectangleArea);
        System.out.println("Area of the circle: " + circleArea);

    }
}

Output:

Area of the rectangle: 15.0
Area of the circle: 19.634954084937497

By modularizing the code, you can create separate functions for calculating the area of each shape, making the code more organised and easier to maintain. In the revised code, the calculateRectangleArea and calculateCircleArea functions have been created to modularize the area calculations. This approach enhances code organisation and readability.

Types of Functions

There are several types of functions, but we’ll focus on four common ones: void, return, functions with parameters, and functions without parameters.

Void Functions:

Void functions do not return any value. In other words, it performs a task or a series of operations without producing a result that can be used elsewhere in the code. Void functions are commonly used for tasks like printing messages to the console, updating variables by reference, or performing specific actions without the need to return a value.

void sayHello() {
   System.out.println("Hello, there!");
}

Return Functions:

Return functions provide a result or value back to the caller. These functions serve the purpose of computing a result or value and returning it to the caller for further use or processing. This return value can be of any data type, including integers, floating-point numbers, strings, or even more complex data structures.

One of the primary benefits of return functions is their ability to encapsulate a specific piece of functionality within a modular and reusable unit. By isolating a task or computation within a function, you can make your code more organised and easier to manage. Additionally, return functions are crucial for obtaining results from calculations, data processing, and various operations within a program.

int add(int a, int b) {
    return a + b;
}

Functions with Parameters:

These functions accept input parameters, which can be used within the function’s logic. Functions with parameters allow you to pass input data into the function, which the function can then use in its logic. Parameters act as placeholders for values that you want to provide when calling the function. 

Using functions with parameters allows you to create reusable code blocks that can perform specific tasks based on the input data provided when calling the function. This makes your code more flexible and adaptable to different scenarios.

void greetUser(String name) {
    System.out.println("Hello, " + name + "!");
}

Functions without Parameters:

Non-parameterized functions, also known as void functions without parameters, are a type of function in programming that do not require any input values (arguments) to perform their tasks. These functions are defined with an empty parameter list, indicating that they don’t expect any data to be passed to them when they are called. Non-parameterized functions are often used for tasks that do not depend on external data and are self-contained within the function body.

void printInfo() {
    System.out.println("This is an informational message.");
}

Non-parameterized functions are useful for encapsulating self-contained tasks or actions within your program. They make your code more organised, modular, and easier to understand, especially when dealing with tasks that don’t rely on external data inputs.

Passing Values and References in Functions

Pass by Value

When you pass a value to a function, it operates on a copy of the original data, leaving the original unchanged.

Code:

Java Code

class NumberWrapper {
    int value;

    NumberWrapper(int value) {
        this.value = value;
    }

    void increment() {
        value += 5;
    }
}

public class Main {
    public static void main(String[] args) {
        NumberWrapper number = new NumberWrapper(10);
        number.increment();

        System.out.println("Inside function: " + number.value);
        System.out.println("Outside function: " + number.value);
    }
}

Output:

Inside function: 15

Outside function: 10

Here, the original number remains unaffected because increment works on a copy of it

Pass by Reference

Passing by reference allows a function to directly modify the original data.

Code:

Java Code

class NumberWrapper {
    int value;

    NumberWrapper(int value) {
        this.value = value;
    }

    void incrementByReference() {
        this.value += 5;
    }
}

public class Main {
    public static void main(String[] args) {
        NumberWrapper number = new NumberWrapper(10);
        number.incrementByReference();

        System.out.println("Inside function: " + number.value);
        System.out.println("Outside function: " + number.value);
    }
}

Output:

Output:

Inside function: 15
Outside function: 15

In this case, the number variable is modified within the incrementByReference function, and the change is reflected outside the function as well.

Pass by Reference in Arrays

Code:

Java Code

void modifyArray(int[] arr) {
    for (int i = 0; i < arr.length; i++) {
        arr[i] *= 2;
    }
}

public static void main(String[] args) {
    int[] myArray = {1, 2, 3, 4, 5};
    modifyArray(myArray);

    for (int num : myArray) {
        System.out.print(num + " ");
    }
    System.out.println();
}

Output:

2 4 6 8 10

Here, the modifyArray function directly modifies the original myArray by doubling each element’s value. When you pass an array to a function, you’re working with a reference to the original array, allowing you to modify it directly.

Special thanks to Gauri Tomar for contributing to this article on takeUforward. If you also wish to share your knowledge with the takeUforward fam, please check out this article