Methods — Parameters, Return Types, Overloading, Varargs, and Method References
In this tutorial, you will learn about Methods. We cover key concepts, practical examples, and best practices to help you master this topic.
Java methods are reusable blocks of code that accept parameters, return values, and can be overloaded with different signatures. Methods are the fundamental unit of behavior in Java — every operation you perform, from System.out.println() to list.sort(), is a method call.
What You'll Learn
- Method declaration syntax and the method signature
- Pass-by-value semantics (including references)
- Method overloading rules
- Varargs and method references (
::)
Why It Matters
Well-designed methods are the key to readable, testable, and maintainable code. Understanding overloading prevents ambiguous calls, and knowing pass-by-value semantics prevents bugs where you expect a method to modify the caller's variable.
Real-World Use
Every framework you use relies on method calls. Spring @Bean methods, JPA Repository methods, and stream pipeline methods all follow the same declaration rules. Method references make functional code more concise.
Method Declaration
A method declaration specifies access modifier, return type, name, parameter list, and body:
public static int add(int a, int b) {
return a + b;
}
public— access modifierstatic— belongs to the class, not instancesint— return typeadd— method name(int a, int b)— parameter listreturn a + b— return statement
The Method Signature
The signature consists of the method name and parameter types: add(int, int). The return type and access modifier are not part of the signature. This distinction matters for overloading.
Parameters and Arguments
Java uses pass-by-value for all parameters:
public static void changeValue(int x) {
x = 100; // only changes the local copy
}
int num = 5;
changeValue(num);
System.out.println(num); // still 5
For reference types, the reference is passed by value:
public static void changeName(StringBuilder sb) {
sb.append(" World"); // modifies the object
sb = new StringBuilder("New"); // does NOT affect caller's reference
}
StringBuilder builder = new StringBuilder("Hello");
changeName(builder);
System.out.println(builder); // "Hello World"
The method can modify the object through the reference, but it cannot change the reference itself.
Return Types
A method declares its return type; void means no return value:
public int square(int x) {
return x * x;
}
public void greet(String name) {
System.out.println("Hello, " + name);
// no return needed
}
Early Returns
public boolean isEven(int number) {
if (number % 2 == 0) {
return true;
}
return false;
}
Returning Arrays and Objects
public int[] getFirstNNumbers(int n) {
int[] result = new int[n];
for (int i = 0; i < n; i++) {
result[i] = i + 1;
}
return result;
}
Method Overloading
Overloading means multiple methods with the same name but different parameter lists:
public int add(int a, int b) {
return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
public double add(double a, double b) {
return a + b;
}
The compiler selects the correct overload based on the argument types and count at compile time. This is compile-time polymorphism.
Rules
- Methods must differ in parameter list (number, type, or order)
- Return type alone is NOT sufficient for overloading
- Changing the access modifier alone is NOT overloading
// INVALID: same signature, different return type
public int calculate() { return 1; }
public double calculate() { return 1.0; } // COMPILE ERROR
Overloading with Autoboxing and Varargs
The compiler resolves overloads in this order:
- Primitive widening (e.g.,
inttolong) - Autoboxing (e.g.,
inttoInteger) - Varargs
public void print(int i) { System.out.println("int: " + i); }
public void print(Integer i) { System.out.println("Integer: " + i); }
public void print(int... i) { System.out.println("varargs"); }
int x = 5;
print(x); // "int: 5" — widening beats boxing
Varargs
Varargs allow a method to accept zero or more arguments of a specified type:
public static int sum(int... numbers) {
int total = 0;
for (int n : numbers) {
total += n;
}
return total;
}
System.out.println(sum()); // 0
System.out.println(sum(1)); // 1
System.out.println(sum(1, 2, 3)); // 6
Rules:
- Only one varargs parameter per method
- It must be the last parameter
- Inside the method, it is treated as an array
public void log(String format, Object... args) {
System.out.printf(format, args);
}
Method References (Java 8+)
Method references provide a shorthand for lambda expressions that call a single method:
List<String> names = List.of("Alice", "Bob", "Charlie");
// Lambda
names.forEach(name -> System.out.println(name));
// Method reference
names.forEach(System.out::println);
Four Types of Method References
| Type | Syntax | Example |
|---|---|---|
| Static method | ClassName::staticMethod |
Math::max |
| Instance method of a particular object | instance::method |
System.out::println |
| Instance method of any object of a specific type | ClassName::instanceMethod |
String::length |
| Constructor | ClassName::new |
ArrayList::new |
// Static method reference
Function<Integer, String> converter = String::valueOf;
// Instance method of an arbitrary object
Function<String, Integer> lengthFunc = String::length;
// Constructor reference
Supplier<List<String>> listSupplier = ArrayList::new;
Common Mistakes
- Confusing pass-by-value with pass-by-reference. Java always passes a copy. For primitives, the method cannot modify the caller's variable. For references, the method can modify the object but not reassign the reference.
- Overloading methods with the same erasure. Due to type erasure,
List<String>andList<Integer>have the same runtime type. Overloading with different generic types compiles but creates ambiguity. - Using varargs in overloaded methods. Calling
sum()matches bothsum(int...)andsum()if it exists, causing ambiguity. - Forgetting the return statement in a non-void method. This is a compile error — the compiler checks all code paths.
- Calling overloaded methods with null.
print(null)whenprint(String)andprint(Integer)both exist: the compiler reports ambiguity because both are equally specific.
Practice Questions
1. Can you have two methods with the same name and parameter list but different return types?
No. The method signature does not include the return type. The compiler would see duplicate method declarations.
2. Does Java pass objects by reference?
No. Java passes object references by value. The method receives a copy of the reference, can modify the object through it, but cannot make the caller's reference point to a different object.
3. What is the difference between a method signature and a method declaration?
The signature is the method name + parameter types. The declaration includes the return type, access modifier, and throws clause.
4. How does the compiler resolve overloaded methods?
It finds methods with matching names, then selects the most specific match using widening, autoboxing, and varargs in that priority order.
5. What is the purpose of method references?
To pass an existing method as a functional argument — a more concise alternative to a lambda when the lambda only calls one existing method.
Challenge Question:
Write a method void assertEquals(Object expected, Object actual) that prints "PASS" if the two objects are equal (using .equals()) and "FAIL" with details otherwise. Then overload it for int, long, and double primitives. Finally, write a varargs version void assertEquals(Object... pairs) that accepts expected/actual pairs.
FAQ
Mini Project
Write a program MethodPlayground.java that:
- Defines a static method
max(int... numbers)that returns the maximum value from varargs - Overloads
max(double... numbers)for doubles - Creates a
printTablemethod that prints a formatted table from a 2Dint[][]with variable column widths - Implements a
repeatmethod using method references:public static void repeat(int n, Runnable action)that callsaction.run()n times - Tests pass-by-value with a method that tries to swap two integers but fails, then shows the correct approach using an array or wrapper
Run each section and verify the output.
What's Next
Methods work with data, and the most common data type in Java is the String. Lesson 10 explores strings in depth — the String pool, immutability, StringBuilder and StringBuffer for efficient concatenation, and text blocks for multi-line strings.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro