Skip to content

Java Methods

In Java, a method is a block of code that performs a specific task. Methods allow you to group related statements, give them a name, and execute them whenever needed by calling that name. This promotes code organization, reusability, and makes programs easier to understand and maintain.

Think of methods like recipes: they have a name (e.g., “bakeCake”), may require ingredients (parameters), perform a series of steps (the method body), and might produce a result (return value, like the baked cake).

You’ve already used methods like System.out.println(). Now, let’s learn how to create your own.

The basic structure (syntax) of a method definition is:

modifier(s) returnType methodName(parameterList) throws ExceptionType(s) {
// Method body: statements that perform the task
// ...
return value; // Required if returnType is not void
}
  • modifier(s): (Optional) Keywords like public, private, protected, static, final, abstract. They control access and behavior. We’ll cover these in detail later.
    • public: Accessible from any other class.
    • static: Belongs to the class itself, not a specific object instance. Can be called using ClassName.methodName().
  • returnType: The data type of the value the method returns. If the method doesn’t return anything, use the keyword void.
  • methodName: The name you give to the method. Follow naming conventions (camelCase, starting with lowercase, e.g., calculateSum, printUserDetails).
  • parameterList: (Optional) A comma-separated list of input variables the method accepts. Each parameter has a type and a name (e.g., int number1, String message). If there are no parameters, leave the parentheses empty ().
  • throws ExceptionType(s): (Optional) Specifies the types of checked exceptions the method might throw. Covered in the Exceptions chapter.
  • Method body: The code block (within {}) containing the statements that implement the method’s logic.
  • return value;: If the returnType is not void, the method must use the return keyword followed by a value of the specified returnType to send a result back to the caller.
/**
* Calculates the sum of two integers.
* @param num1 The first integer.
* @param num2 The second integer.
* @return The sum of num1 and num2.
*/
public static int addNumbers(int num1, int num2) {
int sum = num1 + num2;
return sum; // Returns an integer value
}
/**
* Prints a greeting message to the console.
* This method does not return any value.
* @param name The name to greet.
*/
public static void printGreeting(String name) {
System.out.println("Hello, " + name + "!");
// No return statement needed for void methods (or use 'return;' to exit early)
}

To execute a method, you call (or invoke) it by using its name, followed by parentheses (). If the method requires parameters (arguments), you provide values inside the parentheses, matching the type and order of the parameter list.

  1. Program control transfers to the beginning of the called method.
  2. The method body executes.
  3. Control returns to the point right after the method call when:
    • A return statement is executed (returning a value if applicable).
    • The end of the method body (}) is reached (for void methods).
public class MethodDemo {
public static void main(String[] args) {
// Calling the void method
printGreeting("Alice"); // Pass "Alice" as the argument for the 'name' parameter
// Calling the method that returns a value
int numberA = 10;
int numberB = 25;
int result = addNumbers(numberA, numberB); // Call and store the returned value
System.out.println("The sum is: " + result);
// You can also use the returned value directly
System.out.println("Sum of 5 and 7: " + addNumbers(5, 7));
}
// --- Method definitions from previous example ---
public static int addNumbers(int num1, int num2) {
int sum = num1 + num2;
return sum;
}
public static void printGreeting(String name) {
System.out.println("Hello, " + name + "!");
}
}

Output:

Hello, Alice!
The sum is: 35
Sum of 5 and 7: 12

Pass-by-Value vs. Pass-by-Reference (Clarification)

Section titled “Pass-by-Value vs. Pass-by-Reference (Clarification)”

Java is strictly pass-by-value. This means when you pass a variable to a method:

  • For primitive types (int, float, boolean, etc.): A copy of the variable’s value is passed to the method parameter. Changes made to the parameter inside the method do not affect the original variable outside the method.
  • For reference types (objects, arrays): A copy of the variable’s reference (the memory address) is passed. Both the original variable and the method parameter now point to the same object in memory. Therefore, if the method modifies the object itself (e.g., changes an object’s field, adds an element to an array list), those changes will be reflected outside the method because they are acting on the same object. However, if the method tries to reassign the parameter to a new object (parameter = new Object();), this only changes the parameter’s reference copy and does not affect the original variable outside the method.
public class PassByValuePrimitive {
public static void main(String[] args) {
int originalValue = 10;
System.out.println("Before calling method: " + originalValue);
tryToModify(originalValue);
System.out.println("After calling method: " + originalValue); // Remains 10
}
public static void tryToModify(int number) {
number = number + 5; // Modifies the copy
System.out.println("Inside method: " + number);
}
}

Output:

Before calling method: 10
Inside method: 15
After calling method: 10

Example (Reference Pass-by-Value - Modifying Object State):

Section titled “Example (Reference Pass-by-Value - Modifying Object State):”
import java.util.Arrays;
public class PassByValueReference {
public static void main(String[] args) {
int[] originalArray = {1, 2, 3};
System.out.println("Before calling method: " + Arrays.toString(originalArray));
modifyArray(originalArray);
System.out.println("After calling method: " + Arrays.toString(originalArray)); // Array IS modified
}
// Parameter 'arr' receives a copy of the reference to the original array
public static void modifyArray(int[] arr) {
if (arr != null && arr.length > 0) {
arr[0] = 99; // Modifies the object the reference points to
System.out.println("Inside method: " + Arrays.toString(arr));
}
// arr = new int[]{4, 5, 6}; // This would only change the local 'arr' reference, not originalArray
}
}

Output:

Before calling method: [1, 2, 3]
Inside method: [99, 2, 3]
After calling method: [99, 2, 3]

Method overloading allows you to define multiple methods within the same class that share the same name, as long as their parameter lists are different. The difference can be in:

  • The number of parameters.
  • The data types of the parameters.
  • The order of the data types of parameters.

The return type alone is not sufficient to overload a method.

Overloading allows you to provide different ways to perform a similar operation based on the input arguments. The compiler determines which overloaded method to call based on the arguments provided in the method call.

public class OverloadDemo {
public static void main(String[] args) {
System.out.println("Sum of 2 ints: " + add(5, 10));
System.out.println("Sum of 3 ints: " + add(5, 10, 15));
System.out.println("Sum of 2 doubles: " + add(3.5, 2.7));
printInfo("Alice");
printInfo("Bob", 30);
}
// Overloaded add methods
public static int add(int a, int b) {
System.out.println("-> Called add(int, int)");
return a + b;
}
public static int add(int a, int b, int c) {
System.out.println("-> Called add(int, int, int)");
return a + b + c;
}
public static double add(double a, double b) {
System.out.println("-> Called add(double, double)");
return a + b;
}
// Overloaded printInfo methods
public static void printInfo(String name) {
System.out.println("-> Called printInfo(String)");
System.out.println("Name: " + name);
}
public static void printInfo(String name, int age) {
System.out.println("-> Called printInfo(String, int)");
System.out.println("Name: " + name + ", Age: " + age);
}
}

Output:

-> Called add(int, int)
Sum of 2 ints: 15
-> Called add(int, int, int)
Sum of 3 ints: 30
-> Called add(double, double)
Sum of 2 doubles: 6.2
-> Called printInfo(String)
Name: Alice
-> Called printInfo(String, int)
Name: Bob, Age: 30

A constructor is a special type of method used to initialize objects when they are created using the new keyword. It looks similar to a regular method but has specific rules:

  • It must have the same name as the class.
  • It has no explicit return type, not even void.
  • It is called automatically when an object of the class is instantiated (new ClassName(...)).

Constructors are primarily used to set initial values for an object’s instance variables (fields).

If you don’t define any constructor in your class, Java provides a default constructor automatically. This default constructor takes no arguments and initializes instance variables to their default values (0 for numbers, false for boolean, null for objects).

However, if you do define any constructor (with or without parameters), the default constructor is not provided automatically.

Like regular methods, constructors can be overloaded.

class Dog {
String name;
int age;
// Constructor 1: No arguments (initializes with default name)
public Dog() {
this.name = "Unknown"; // 'this' refers to the current object
this.age = 0;
System.out.println("Dog() constructor called.");
}
// Constructor 2: Takes name as argument
public Dog(String name) {
this.name = name;
this.age = 0;
System.out.println("Dog(String) constructor called.");
}
// Constructor 3: Takes name and age
public Dog(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Dog(String, int) constructor called.");
}
public void displayInfo() {
System.out.println("Dog [Name=" + name + ", Age=" + age + "]");
}
}
public class ConstructorDemo {
public static void main(String[] args) {
Dog dog1 = new Dog(); // Calls Dog()
Dog dog2 = new Dog("Buddy"); // Calls Dog(String)
Dog dog3 = new Dog("Lucy", 3); // Calls Dog(String, int)
dog1.displayInfo();
dog2.displayInfo();
dog3.displayInfo();
}
}

Output:

Dog() constructor called.
Dog(String) constructor called.
Dog(String, int) constructor called.
Dog [Name=Unknown, Age=0]
Dog [Name=Buddy, Age=0]
Dog [Name=Lucy, Age=3]

Introduced in Java 5, varargs allow a method to accept a variable number of arguments of the same type.

Syntax: In the method signature, specify the type followed by an ellipsis (...).

`public static void myMethod(String fixedArg, int... numbers)`
  • The varargs parameter (int... numbers in the example) is treated as an array of that type (int[]) inside the method.
  • A method can have only one varargs parameter.
  • The varargs parameter must be the last parameter in the method signature.
  • You can call the method with zero or more arguments for the varargs parameter, or pass an array of the specified type.
public class VarargsDemo {
public static void main(String[] args) {
printNumbers("Set 1:", 1, 2, 3);
printNumbers("Set 2:", 10, 20, 30, 40, 50);
printNumbers("Set 3:"); // Call with zero varargs
int[] data = {100, 200};
printNumbers("Set 4:", data); // Call with an array
}
// Method accepts a title and a variable number of integers
public static void printNumbers(String title, int... numbers) {
System.out.print(title + " ");
if (numbers.length == 0) {
System.out.println(" (No numbers)");
return;
}
for (int i = 0; i < numbers.length; i++) {
System.out.print(numbers[i]);
if (i < numbers.length - 1) {
System.out.print(", ");
}
}
System.out.println();
}
}

Output:

Set 1: 1, 2, 3
Set 2: 10, 20, 30, 40, 50
Set 3: (No numbers)
Set 4: 100, 200

The main method, the entry point of a Java application, has a parameter String[] args (or String... args). This array receives any arguments passed to the program on the command line when it’s executed.

public class CommandLineArgs {
public static void main(String[] args) {
System.out.println("Number of arguments received: " + args.length);
if (args.length > 0) {
System.out.println("Arguments are:");
for (int i = 0; i < args.length; i++) {
System.out.println("args[" + i + "]: " + args[i]);
}
}
}
}

Compile and Run:

Terminal window
javac CommandLineArgs.java
java CommandLineArgs firstArg "Second Argument" 123

Output:

Number of arguments received: 3
Arguments are:
args[0]: firstArg
args[1]: Second Argument
args[2]: 123

Note: Arguments are passed as Strings. If you need numbers, you’ll need to parse them (e.g., using Integer.parseInt()).

The finalize() Method (Deprecated - Avoid Use)

Section titled “The finalize() Method (Deprecated - Avoid Use)”

Older Java versions had a finalize() method (defined in Object). The intention was for it to be overridden to perform cleanup actions just before an object was garbage collected. However, finalize() has significant drawbacks:

  • Unpredictable Timing: There’s no guarantee when or even if finalize() will be called.
  • Performance Issues: Finalization can delay garbage collection and impact performance.
  • Error Prone: Exceptions thrown in finalize() are ignored.
  • Security Risks: Can potentially resurrect objects.

finalize() has been deprecated since Java 9 and should be avoided. Modern alternatives for resource cleanup include:

  • try-with-resources: The standard way to manage resources that need explicit closing (like I/O streams, network sockets, database connections).
  • java.lang.ref.Cleaner (Java 9+): A more reliable and flexible mechanism for registering cleanup actions for objects when they become unreachable.

Methods are the workhorses of Java programs. Understanding how to define, call, and organize them is crucial. The next chapters will explore more advanced concepts built upon methods and classes, starting with how to handle errors using Java Exceptions.