Functions (Methods) in Java
Define and call methods, work with parameters, return types, method overloading, varargs, and lambda expressions in Java.
Method Basics & Execution Flow
In Java, functions are called **methods**. Every method belongs to a class. You declare a method with a return type, a name, and an optional list of parameters. `void` means the method returns nothing.
1. Creating and Calling a Method
A `static` method can be called directly from `main` without creating an object.
2. Method Execution Flow
Execution jumps to the method, runs its body, then returns to the line after the call.
3. Return Values
Declare the return type instead of `void`, and use `return` to send a value back to the caller.
Parameters & Arguments
Java uses **pass-by-value** — primitives are copied, objects pass a copy of the reference. Java has no built-in default parameters; use **method overloading** to simulate them.
1. Basic Parameters
Parameters are declared in the method signature; arguments are the values you pass when calling.
2. Optional / Default Parameters (via Overloading)
Java has no default parameter syntax. Use overloaded methods — one delegates to the other with a default.
3. Named Parameters (via Builder / Object)
Java has no named argument syntax. Pass a configuration object or use the Builder pattern to name your parameters.
Varargs (Unlimited Parameters)
Java varargs (`Type... name`) let a method accept zero or more arguments of a given type. Inside the method, the parameter behaves like an array. A varargs parameter must be last in the signature.
1. Varargs
Use `Type... name` to accept any number of arguments. The caller can pass individual values or nothing at all.
2. Passing an Array to a Varargs Method
You can pass an existing array directly to a varargs parameter — Java spreads it automatically.
Method Forms
Java methods come in several forms: `static` (class-level), instance (object-level), anonymous **lambda expressions** (Java 8+), and **method references** as shorthand lambdas.
1. Static vs Instance Methods
`static` methods belong to the class; instance methods belong to an object and can access its fields.
2. Anonymous Functions (Lambda Expressions — Java 8+)
Lambdas are anonymous functions assigned to functional interface variables. Use them for callbacks, sorting, and stream operations.
3. Method References (Java 8+)
A method reference (`ClassName::method`) is shorthand for a lambda that only calls a single method.
Method Overloading
Java allows multiple methods with the same name as long as their **parameter lists differ** (type, count, or order). The compiler picks the right version at compile time — this is called **static dispatch**.
1. Basic Overloading
Same method name, different parameter signatures. Java resolves which one to call at compile time.
Pass-by-Value in Java
Java is **always pass-by-value**. For primitives the value is copied; for objects a copy of the **reference** is passed. Mutating the object's fields is visible to the caller, but reassigning the parameter variable is not.
1. Primitives Are Copied
Changing a primitive parameter inside a method does not affect the caller's variable.
2. Object References Are Copied
Mutating the object's fields is visible to the caller; reassigning the reference is not.
Higher-Order Methods (Custom Implementation)
A **higher-order method** accepts a function as a parameter or returns one. In Java this is done with functional interfaces (`Function`, `Predicate`, `Consumer`, etc.). Building these from scratch shows exactly how the Stream API works internally.
1. What is a Higher-Order Method?
A method that takes a function (lambda / method reference) as a parameter — making it reusable with any logic.
2. Creating map() from Scratch
Build a map method using `Function<T, R>` — transform each element and collect results into a new list.
3. Creating filter() from Scratch
Build a filter method using `Predicate<T>` — keep only elements that match a condition.
4. Creating reduce() from Scratch
Build a reduce method using `BinaryOperator<T>` — accumulate all elements into one value.
5. Creating forEach() from Scratch
Build a forEach method using `Consumer<T>` — run a side-effect action on every element.
6. Creating find() from Scratch
Build a find method using `Predicate<T>` — return the first matching element, or `null` if not found.
7. Creating findIndex() from Scratch
Build a findIndex method — return the index of the first matching element, or `-1` if not found.
8. Creating some() & every() from Scratch
Build `some` (any match) and `every` (all match) methods using `Predicate<T>`.
9. Creating group() from Scratch
Build a group method using `Function<T, K>` — group list elements into a `Map` by a key derived from each element.
10. Creating a Custom Higher-Order Method
Write your own method that accepts a function as a parameter using `java.util.function` interfaces, then use it just like the built-in stream methods.
Closures & State
What is a Closure?
A lambda that captures variables from its enclosing scope.
Stateful Closure — Counter
Maintain private state across calls using an array workaround.
Closure as a Configurable Function
Bake a parameter into a returned lambda (partial application).
Closure in Loops — Effectively Final
Loop variables cannot be captured — copy to a local final variable.
Closure for Memoization
Cache expensive results in a privately captured Map.