Methods & Functions
Method declaration, parameters, and return types
1. Method Basics
Methods are reusable blocks of code that perform specific tasks. They help organize code, reduce repetition, and make programs easier to understand and maintain.
Method Structure
Access Modifier
static
Return Type
methodName
(parameters)
{ method body }
Basic Method Syntax
public class Calculator {
// Method with return value
public static int add(int a, int b) {
return a + b;
}
// Method without return value
public static void printResult(int result) {
System.out.println("Result: " + result);
}
// Method without parameters
public static void welcome() {
System.out.println("Welcome to Calculator!");
}
}
Access Modifiers
Control visibility: public, private, protected
Return Type
Data type returned: int, String, void
Method Name
Descriptive identifier following camelCase
Parameters
Input values passed to the method
2. Parameters & Arguments
Parameters are variables defined in a method signature, while arguments are the actual values passed when calling the method.
Parameter Flow
1
Method Call
add(5, 3)
2
Parameters
int a = 5, int b = 3
3
Processing
return a + b
4
Return
8
Parameter Types
public class ParameterExamples {
// Primitive parameters (pass by value)
public static void modifyPrimitive(int x) {
x = 100; // Original value unchanged
}
// Object parameters (pass by reference)
public static void modifyArray(int[] arr) {
arr[0] = 999; // Original array modified
}
// Variable arguments (varargs)
public static int sum(int... numbers) {
int total = 0;
for (int num : numbers) {
total += num;
}
return total;
}
public static void main(String[] args) {
// Primitive example
int value = 10;
modifyPrimitive(value);
System.out.println(value); // Still 10
// Array example
int[] numbers = {1, 2, 3};
modifyArray(numbers);
System.out.println(numbers[0]); // Now 999
// Varargs examples
System.out.println(sum(1, 2, 3)); // 6
System.out.println(sum(1, 2, 3, 4, 5)); // 15
}
}
3. Method Overloading
Method overloading allows multiple methods with the same name but different parameter lists. The compiler determines which method to call based on the arguments.
Overloaded Method Signatures
calculate(int a, int b)- Additioncalculate(double a, double b)- Double Additioncalculate(int a, int b, int c)- Triple Additioncalculate(String operation, int a, int b)- Operation
Overloaded Methods
public class MathUtils {
// Overloaded methods - same name, different parameters
// Two integers
public static int calculate(int a, int b) {
return a + b;
}
// Two doubles
public static double calculate(double a, double b) {
return a + b;
}
// Three integers
public static int calculate(int a, int b, int c) {
return a + b + c;
}
// String operation with two integers
public static int calculate(String operation, int a, int b) {
switch(operation) {
case "+": return a + b;
case "-": return a - b;
case "*": return a * b;
case "/": return a / b;
default: return 0;
}
}
public static void main(String[] args) {
System.out.println(calculate(5, 3)); // 8
System.out.println(calculate(5.5, 3.2)); // 8.7
System.out.println(calculate(1, 2, 3)); // 6
System.out.println(calculate("*", 4, 5)); // 20
}
}
4. Static vs Instance Methods
Understanding the difference between static and instance methods is crucial for proper object-oriented design.
Static Methods
- Belong to the class
- Called without object creation
- Cannot access instance variables
- Shared by all instances
Instance Methods
- Belong to object instances
- Require object creation
- Can access instance variables
- Unique to each instance
Static vs Instance Example
public class BankAccount {
// Instance variables
private String accountHolder;
private double balance;
// Static variable
private static int totalAccounts = 0;
// Constructor
public BankAccount(String holder, double initialBalance) {
this.accountHolder = holder;
this.balance = initialBalance;
totalAccounts++; // Increment static counter
}
// Instance method - operates on specific account
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println("Deposited $" + amount);
}
}
// Instance method - returns instance data
public double getBalance() {
return balance;
}
// Static method - operates on class-level data
public static int getTotalAccounts() {
return totalAccounts;
}
// Static utility method
public static double calculateInterest(double principal, double rate) {
return principal * rate / 100;
}
public static void main(String[] args) {
// Static method call - no object needed
System.out.println("Interest: $" +
BankAccount.calculateInterest(1000, 5)); // $50.0
// Create objects for instance methods
BankAccount account1 = new BankAccount("Alice", 1000);
BankAccount account2 = new BankAccount("Bob", 2000);
// Instance method calls
account1.deposit(500);
System.out.println("Alice's balance: $" + account1.getBalance()); // $1500
// Static method call
System.out.println("Total accounts: " +
BankAccount.getTotalAccounts()); // 2
}
}
5. Variable Scope & Lifetime
Variable scope determines where a variable can be accessed. Understanding scope prevents bugs and helps write cleaner code.
Scope Hierarchy
- Class Scope: static variables, instance variables
- Method Scope: parameters, local variables
- Block Scope: loop variables, if block variables
Scope Examples
public class ScopeExample {
// Class-level variables
static int classVariable = 100; // Static - shared by all
int instanceVariable = 200; // Instance - per object
public void demonstrateScope() {
// Method-level variable
int methodVariable = 300;
System.out.println("Class variable: " + classVariable); // Accessible
System.out.println("Instance variable: " + instanceVariable); // Accessible
System.out.println("Method variable: " + methodVariable); // Accessible
// Block scope
if (true) {
int blockVariable = 400;
System.out.println("Block variable: " + blockVariable); // Accessible
System.out.println("Method variable: " + methodVariable); // Still accessible
}
// System.out.println(blockVariable); // Error - out of scope
// Loop scope
for (int i = 0; i 3; i++) {
int loopVariable = i * 10;
System.out.println("Loop variable: " + loopVariable); // Accessible
}
// System.out.println(i); // Error - loop variable out of scope
}
public static void staticMethod() {
System.out.println("Class variable: " + classVariable); // Accessible
// System.out.println(instanceVariable); // Error - no instance context
// Need instance to access instance variables
ScopeExample obj = new ScopeExample();
System.out.println("Instance variable: " + obj.instanceVariable); // Now accessible
}
}
6. Recursion Basics
Recursion is a technique where a method calls itself to solve a problem by breaking it into smaller subproblems.
Factorial Recursion: factorial(4)
4
factorial(4)
4 * factorial(3)
3
factorial(3)
3 * factorial(2)
2
factorial(2)
2 * factorial(1)
1
factorial(1)
return 1 (base case)
Result: 4 * 3 * 2 * 1 = 24
Recursion Examples
public class RecursionExamples {
// Classic factorial
public static long factorial(int n) {
// Base case - stops recursion
if (n 1) {
return 1;
}
// Recursive case - method calls itself
return n * factorial(n - 1);
}
// Fibonacci sequence
public static int fibonacci(int n) {
if (n 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
// Power calculation
public static double power(double base, int exponent) {
// Base cases
if (exponent == 0) return 1;
if (exponent == 1) return base;
// Recursive cases
if (exponent > 0) {
return base * power(base, exponent - 1);
} else {
return 1 / power(base, -exponent);
}
}
// Binary search (recursive)
public static int binarySearch(int[] arr, int target, int left, int right) {
if (left > right) {
return -1; // Not found
}
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] > target) {
return binarySearch(arr, target, left, mid - 1);
} else {
return binarySearch(arr, target, mid + 1, right);
}
}
public static void main(String[] args) {
System.out.println("5! = " + factorial(5)); // 120
System.out.println("Fib(6) = " + fibonacci(6)); // 8
System.out.println("2^8 = " + power(2, 8)); // 256.0
int[] sortedArray = {1, 3, 5, 7, 9, 11, 13};
int index = binarySearch(sortedArray, 7, 0, sortedArray.length - 1);
System.out.println("Found 7 at index: " + index); // 3
}
}
7. Best Practices
Following best practices when writing methods leads to cleaner, more maintainable code.
Clean Method Examples
public class CleanMethodExamples {
// Good: Clear, specific name
public static boolean isValidEmail(String email) {
return email != null && email.contains("@") && email.contains(".");
}
// Good: Single responsibility
public static double calculateDiscount(double price, int discountPercent) {
return price * discountPercent / 100.0;
}
// Good: Input validation
public static int divide(int dividend, int divisor) {
if (divisor == 0) {
throw new IllegalArgumentException("Division by zero");
}
return dividend / divisor;
}
// Good: Using objects for complex parameters
public static class OrderRequest {
private String productId;
private int quantity;
private String customerId;
private boolean expressShipping;
public OrderRequest(String productId, int quantity,
String customerId, boolean expressShipping) {
this.productId = productId;
this.quantity = quantity;
this.customerId = customerId;
this.expressShipping = expressShipping;
}
// Getters
public String getProductId() { return productId; }
public int getQuantity() { return quantity; }
public String getCustomerId() { return customerId; }
public boolean isExpressShipping() { return expressShipping; }
}
// Instead of: processOrder(String id, int qty, String customer, boolean express, ...)
public static boolean processOrder(OrderRequest request) {
System.out.println("Processing order for: " + request.getCustomerId());
System.out.println("Product: " + request.getProductId());
System.out.println("Quantity: " + request.getQuantity());
return true;
}
// Good: Utility methods for common operations
public static String formatCurrency(double amount) {
return String.format("$%.2f", amount);
}
public static boolean isEmpty(String str) {
return str == null || str.trim().isEmpty();
}
}
Quick Reference
Access Modifiers:
public- Accessible everywhereprivate- Only within same classprotected- Package + subclasses(default)- Package-level access
Common Patterns:
static- Class-level methodfinal- Cannot be overriddenint... args- Variable arguments@Override- Override parent method