Last 30 Days
No notifications
In Java, every method lives inside a class. Unlike Python or JavaScript, you can't define a free-standing function. The signature is:
[modifiers] returnType name(paramType paramName, ...) {
// body
return value;
}public class MathUtil {
// a static method — call without an instance
public static int square(int x) {
return x * x;
} // an instance method — needs new MathUtil()
public double cube(double x) {
return x * x * x;
}
}
// usage
int s = MathUtil.square(5); // 25
double c = new MathUtil().cube(2.5); // 15.625
public static int max(int a, int b) { return a > b ? a : b; }
public static double max(double a, double b) { return a > b ? a : b; }
public static int max(int a, int b, int c) { return max(max(a, b), c); }The compiler picks the right one by argument types and count. Return type alone is NOT enough to overload.
public static int sum(int... nums) {
int total = 0;
for (int n : nums) total += n;
return total;
}sum(); // 0
sum(1, 2, 3); // 6
sum(new int[]{1,2}); // 3
public static long factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}public static int add(int a, int b) {
return a + b;
}
// ^ ^ ^ ^ ^ ^ ^
// └ method body
// └ parameter list
// └ method name
// └ return type (use void for no return)
// └ "static" — belongs to the class, not an instance
// | └ access modifier
// └ optional access scope| Modifier | Visibility | |||
public | everyone | |||
protected | same package + subclasses | |||
| (none / package-private) | same package | |||
private | same class only |
| static | instance |
| Belongs to | the class | each object | ||
| Call as | Math.sqrt(2) | obj.sqrt(2) | ||
Has this? | No | Yes | ||
| Common use | utility functions, factory methods | object behaviour |
public class Counter {
static int totalCounters = 0; // shared across all instances
int count; // per-instance public Counter() { totalCounters++; }
public void inc() { count++; }
public int get() { return count; }
public static int howMany() { return totalCounters; }
}
Java has only pass-by-value. But for reference types, the *value being passed* IS a reference (a pointer to the object). So:
static void reassign(int[] arr) {
arr = new int[]{99}; // local variable now points elsewhere
}
static void mutate(int[] arr) {
arr[0] = 99; // modifies the SAME array the caller has
}public static void main(String[] a) {
int[] x = {1, 2, 3};
reassign(x);
System.out.println(x[0]); // 1 (caller's reference unchanged)
mutate(x);
System.out.println(x[0]); // 99 (caller's array WAS mutated)
}
> Rule of thumb: you can't change what the caller's variable POINTS to, but you can mutate the object behind that reference.
Multiple methods with the same name but different parameter lists:
public class Printer {
public static void show(int x) { System.out.println("int " + x); }
public static void show(double x) { System.out.println("double " + x); }
public static void show(String x) { System.out.println("string " + x); }
public static void show(int x, int y) { System.out.println("two ints " + x + ", " + y); }
}Resolution rules (the compiler picks the best fit):
1. Exact match wins (show(5) → int overload).
2. Then widening primitives (int → long → double).
3. Then autoboxing (int → Integer).
4. Then varargs.
> Return type alone CANNOT distinguish overloads — the compiler refuses.
public static String join(String sep, String... parts) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < parts.length; i++) {
if (i > 0) sb.append(sep);
sb.append(parts[i]);
}
return sb.toString();
}join(", ", "a", "b", "c"); // "a, b, c"
Rules:
String[]).Java has no default parameters. The idiomatic substitute is overloading:
public static String greet(String name) { return greet(name, "Hello"); }
public static String greet(String name, String hi) { return hi + ", " + name + "!"; }greet("Asha"); // "Hello, Asha!"
greet("Asha", "Welcome"); // "Welcome, Asha!"
public static int fib(int n) {
if (n < 2) return n;
return fib(n - 1) + fib(n - 2); // O(2^n) — slow
}For deep recursion, use memoisation or convert to iteration. The default JVM stack is ~512 KB → roughly 10⁴ frames before StackOverflowError.
return and voidvoid method must return on every code path.void methods can use return; (no value) to exit early.public static int abs(int n) {
if (n < 0) return -n;
return n; // every path covered
}public static void greet(String name) {
if (name == null) return;
System.out.println("Hi " + name);
}
Once you know lambdas, you can pass methods as values:
import java.util.function.*;Function<Integer, Integer> sq = MathUtil::square;
sq.apply(5); // 25
Full coverage in the lambdas topic.
computeTotal, getUserById.save, delete, render.isXxx / hasXxx: isEmpty(), hasNext().| Bug | Fix | |||
Forgot return on a code path | Compiler tells you — fix the missing branch | |||
| Tried to overload by return type only | Add a parameter difference | |||
| Mutating a parameter and expecting caller to see reassignment | Java is pass-by-value; return the new value | |||
| Calling instance method without an object | Add static or instantiate (new MyClass().foo()) | |||
| Recursive call without base case | Add a termination condition | Cheat-Sheet | Need | Code |
| Define static method | static int f(int x) { ... } | |||
| Call static method | ClassName.method(args) | |||
| Variable args | int sum(int... ns) | |||
| Overload | Same name, different params | |||
| Pass array as varargs | sum(new int[]{1,2,3}) | |||
| Early exit (void) | return; | |||
| Recursion limit | ~10⁴ frames before StackOverflow |
You can now organise code into reusable methods. Next: strings — Java's most-used object.