Functions/Methods in Java
A method is a block of code which only runs when it is called.
To reuse the code: define the code once & use it many times
Syntax
<access modifier> <return type> <method name>(<parameter list>) {
// method body
return <value>;
}
Now, let's break down this syntax and understand what it means:
Access Modifier: A keyword such as public, private, or protected that defines the visibility or accessibility of a method.
Return type: The data type of the value returned by the method, or void if the method does not return a value.
Method name: This is the name given to the method. It should follow Java's naming conventions.
Parameter list: The parameter list of a method is like a set of instructions that tells the method what kind of information it can expect to receive when it's called. It's like a list of variables that the method needs to perform its task.
Method Body: The code that performs a specific task when the method is called.
Return value: This statement is used to return a value from the method. The
<value>
should match the data type specified in the<return type>
.
Putting it all together, a complete method looks like this
public int addNumbers(int a, int b) {
// method body
int sum = a + b;
return sum;
}
In this example:
The access modifier is
public
.The return type is
int
.The method name is
addNumbers
.The parameter list is
(int a, int b)
.The method body calculates the sum of
a
andb
.The method returns an
int
value (the sum).
Return type:
A return statement causes the program control to transfer back to the caller of a method.
A return type may be a primitive type like int, char, or void type(returns nothing).
There are a few important things to understand about returning the values:
The type of data returned by a method must be compatible with the return type specified by the method
eg: if the return type of some method is String we cannot return an integer
public class Example { // This method has a return type of String public String getStringValue() { // Valid return statement return "Hello, World!"; // Invalid return statement (compilation error) // return 42; } }
The variable receiving the value returned by a method must also be compatible with the return type specified for the method
public class Example {
public String getStringValue() {
return "Hello, World!";
}
public static void main(String[] args) {
Example example = new Example();
// Valid usage, as the method returns a String and the variable is of type String
String result = example.getStringValue();
// Invalid usage (compilation error), as the method returns a String, but the variable is of type int
// int intValue = example.getStringValue();
}
}
Pass by value
Let us understand Pass by Value from this example:
public class PassingExample {
public static void main(String[] args) {
String name = "a";
ChangeName(name);
}
static void ChangeName(String naam) {
System.out.println(naam);
}
}
// The output will be a.
The value of the
name
variable (which is a reference to the string object "a") is passed to theChangeName
method.The
naam
parameter in theChangeName
method receives a copy of the value of the reference (memory address) to the same string object.
Here, both name
and naam
reference the same string object. If you were to modify the string object through either name
or naam
, the change would be reflected in both variables. For example, if you were to change the content of the string through naam
, it would also affect the content when accessing name
afterward.
But in the below example even after changing the content of the String through naam
it didn't affect the content when accessing name
afterward. That's because it is not changing the original object, it's creating a new object. Since it is created inside the function it will not change the original one.
public class PassingExample {
public static void main(String[] args) {
String name = "a"; //Name -> a <- Naam
ChangeName(name);
System.out.println(name);
}
static void ChangeName(String naam) {
naam = "b";
//Not changing the original object,just creating a new object
// Naam -> b
// Name -> a
}
}
//The output is a.
Points to be noted:
Primitive data types like int, short, char, byte, etc just pass value.
These are generally passed by value.
When you pass a primitive type to a function or assign it to another variable, a copy of the actual value is passed or assigned.
Any changes made to the parameter or variable inside the function or in a different scope do not affect the original value.
void modifyValue(int x) {
x = 10; // Changes to x don't affect the original value outside the function
}
int main() {
int value = 5;
modifyValue(value);
// 'value' is still 5 here
}
Object and reference pass value of reference variable
When dealing with objects, the situation is a bit different. In languages like Java, references to objects are passed by value.
When you pass an object to a function or assign it to another variable, you are actually passing the reference (memory address) to the object.
The contents of the object can be modified through this reference, and changes are reflected outside the function.
class MutableObject {
int value;
MutableObject(int value) {
this.value = value;
}
}
void modifyObject(MutableObject obj) {
obj.value = 10; // Changes to obj affect the original object outside the function
}
public static void main(String[] args) {
MutableObject myObject = new MutableObject(5);
modifyObject(myObject);
// 'myObject.value' is now 10
}
Scope
Function scope: Variables declared inside a method/function scope (means inside method) can't be accessed outside the method.
public class FunctionScopeExample {
public static void main(String[] args) {
myFunction();
// Uncommenting the line below would result in a compilation error
// System.out.println(localVar);
}
static void myFunction() {
int localVar = 10; // localVar is only accessible within myFunction
System.out.println("Inside myFunction - localVar: " + localVar);
}
}
Block scope: Variables declared inside a block are only accessible within that block. Once you exit the block, the variables declared within it go out of scope and cannot be accessed anymore.
public class BlockScopeExample {
public static void main(String[] args) {
int outsideVar = 5; // 'outsideVar' is declared and initialized outside the block
{
int insideVar = 10; // 'insideVar' is declared and initialized inside the block
System.out.println("Inside the block - outsideVar: " + outsideVar + ", insideVar: " + insideVar);
outsideVar = 15; // 'outsideVar' can be updated inside the block
System.out.println("Inside the block - updated outsideVar: " + outsideVar);
}
// Uncommenting the line below would result in a compilation error
// System.out.println("Outside the block - insideVar: " + insideVar);
outsideVar = 20; // 'outsideVar' can be updated outside the block
System.out.println("Outside the block - final outsideVar: " + outsideVar);
}
}
Loop scope: Variables declared inside the loop have loop scope.
public class LoopScopeExample {
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
// Variable 'loopVar' is declared inside the loop and has loop scope
int loopVar = i;
System.out.println("Inside the loop - loopVar: " + loopVar);
}
// Uncommenting the line below would result in a compilation error
// System.out.println("Outside the loop - loopVar: " + loopVar);
}
}
Shadowing
Shadowing in Java is the practice of using variables in overlapping scopes with the same name where the variable in low-level scope overrides the variable of high-level scope. Here the variable at the high-level scope is shadowed by the low-level scope variable.
public class ShadowingExample {
// Outer variable
private static int x = 5;
public static void main(String[] args) {
// Outer variable 'x' is accessible here
System.out.println("Outer variable x: " + x);
// Declaring a variable with the same name 'x' within this block
int x = 10;
// Inner variable 'x' shadows the outer variable within this block
System.out.println("Inner variable x: " + x);
// You can still access the outer variable using the class name
System.out.println("Outer variable x (using class name): " + ShadowingExample.x);
// Calling a method with a parameter named 'x'
printX(15);
}
// Method with a parameter named 'x'
static void printX(int x) {
// The parameter 'x' shadows the outer variable within this method
System.out.println("Parameter x: " + x);
}
}
Variable Arguments
Variable Arguments is used to take a variable number of arguments. A method that takes a variable number of arguments is a varargs method.
First, let’s look at the example without using varargs:
class NoVararg {
public int sumNumber(int a, int b){
return a+b;
}
public int sumNumber(int a, int b, int c){
return a+b+c;
}
public static void main( String[] args ) {
NoVararg object = new NoVararg();
System.out.println(object.sumNumber(1, 2));
System.out.println(object.sumNumber(1, 2, 3));
}
}
// The ouput will be 3
6
As you can see, we have to overload sumNumber()
method to make it work for 3 arguments.
What if the user wants to add 5 numbers or 10 or 100?
This can be handled neatly with the use of varargs. Let’s see a code example:
class VarargExample {
public int sumNumber(int ... args){
System.out.println("argument length: " + args.length);
int sum = 0;
for(int x: args){
sum += x;
}
return sum;
}
public static void main( String[] args ) {
VarargExample ex = new VarargExample();
int sum2 = ex.sumNumber(2, 4);
System.out.println("sum2 = " + sum2);
int sum3 = ex.sumNumber(1, 3, 5);
System.out.println("sum3 = " + sum3);
int sum4 = ex.sumNumber(1, 3, 5, 7);
System.out.println("sum4 = " + sum4);
}
}
//The output will be
argument length: 2
sum2 = 6
argument length: 3
sum3 = 9
argument length: 4
sum4 = 16
Here, the sumNumber()
method returns the sum of int
parameters passed to it (doesn't matter the number of arguments passed).
Method overloading
Method overloading happens when two functions have the same name.
public class MyClass {
// Compilation Error: Duplicate method with the same signature
public void myMethod(int x, int y) {
// Some code
}
// Error: Duplicate method with the same signature
public void myMethod(int x, int y) {
// Some other code
}
public static void main(String[] args) {
// Code
}
}
In this example, attempting to compile this code will result in a compilation error because both myMethod
methods have the same name and the same parameter types.
If you want to have multiple methods with the same name, they must differ in either the number or types of their parameters. This concept is known as method overloading.
public class MethodOverloading {
public int add(int a,int b) {
return a + b;
}
public int add(int a,int b,int c) {
return a + b + c;
}
This is allowed to have different arguments with the same method name. At compile time, it decides which function to run.
Thanks for reading:)
Subscribe to my newsletter
Read articles from Saswat Pal directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Saswat Pal
Saswat Pal
Hi there! I'm a computer science student with a keen interest in Java programming and Data Structures & Algorithms. Currently, I am honing my skills in these areas and also familiar with C, C++. As an aspiring developer, I am always open to new opportunities and collaborations that allow me to learn and grow. Let's connect and create something great together!