skip to content

Recursion

Recursion in Java: base cases, the stack frames each call consumes, and the fact that the JVM does not eliminate tail calls. Interviewers ask about depth limits and StackOverflowError to see whether you know when to convert recursion into iteration.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

5

What is recursion in Java, and why must a recursive method have a base case?

level: juniorimportance: must knowfreq 80%

answer

  1. Method calls itself on a smaller subproblem
  2. Base case = stop condition, no recursion
  3. Recursive case must shrink toward the base case
  4. No base case -> infinite recursion -> StackOverflowError
  5. Winds down to base, unwinds back up

basics

~20 s

Recursion is when a method calls itself to solve a smaller piece of a problem. The base case is the simple input that stops the calling, so the method does not call itself forever and eventually returns an answer.

solid answer

~40 s

Recursion is a technique where a method solves a problem by calling itself on a smaller or simpler version of the same problem. Every correct recursive method needs two parts: a base case, a condition simple enough to answer directly without recursing, and a recursive case that reduces the input and calls the method again, moving toward the base case. Without a base case (or if the recursive case never approaches it) the calls never stop and the program eventually exhausts the call stack and throws StackOverflowError. A classic example is factorial: factorial(0) returns 1 (base case), and factorial(n) returns n * factorial(n-1) (recursive case). Recursion is a natural fit for self-similar problems like tree traversal, where each subtree is handled by the same logic.

code

java · 8 lines
java
static long factorial(int n) {
    if (n == 0) {        // base case: stop recursing
        return 1;
    }
    return n * factorial(n - 1); // recursive case: shrink toward base
}

// factorial(3) -> 3 * factorial(2) -> ... -> 3*2*1*1 == 6

go deeper

for a junior

Defines recursion as a method calling itself, identifies the base case as the stop condition, and can trace a simple example like factorial.

for a middle

Explains both base and recursive cases, notes the recursive case must converge toward the base case, and connects a missing base case to StackOverflowError.

for a senior

Frames recursion in terms of the call stack and stack frames, knows when recursion is the right tool (self-similar data, divide-and-conquer) versus a loop, and reasons about correctness/termination.

for a principal

Discusses recursion as a design choice with cost trade-offs (stack depth, readability), guides teams on when to convert to iteration or accumulate state, and reasons about termination proofs and input bounds.

## What recursion is **Recursion** is a problem-solving technique where a function (in Java, a *method*) is defined in terms of itself: to solve a problem, the method calls *itself* on a smaller or simpler version of that same problem, until the problem becomes trivial enough to answer directly. A **method** is a named block of code you can call. When code 'calls a method', execution jumps into that method, runs it, and then returns to where it was called. A *recursive* method is simply one whose body contains a call to itself. ## Why a base case is mandatory Every correct recursive method must have two parts: 1. **Base case** — a condition that is simple enough to answer *without* recursing. It is where the recursion stops. For `factorial`, the base case is `n == 0`, which returns `1` directly. 2. **Recursive case** — the part that does call the method again, but on a *reduced* input that moves **toward** the base case. For `factorial`, that is `return n * factorial(n - 1)` — each call passes a smaller `n`. If there is **no base case**, or the recursive case never actually approaches the base case (e.g. you pass the same value, or move away from it), the method keeps calling itself indefinitely. This is called **infinite recursion**. ## What the call stack is, and why infinite recursion crashes When any method is called, the JVM allocates a **stack frame** for it — a small block of memory holding that call's local variables, parameters, and the place to return to. These frames are stored on the thread's **call stack**, which has a fixed, limited size. Each *active* recursive call adds another frame; a frame is only freed (popped) when its call **returns**. With infinite recursion, calls keep being made but none ever returns, so frames pile up without limit. When the stack runs out of room, the JVM throws **`java.lang.StackOverflowError`**. This is the runtime symptom of a missing or unreachable base case. ## Worked example ``` factorial(3) = 3 * factorial(2) = 3 * (2 * factorial(1)) = 3 * (2 * (1 * factorial(0))) // factorial(0) hits the base case -> 1 = 3 * (2 * (1 * 1)) = 6 ``` The calls 'wind' down to the base case, then the results 'unwind' back up as each call returns and multiplies. ## Key takeaways - Recursion = a method calling itself on a smaller subproblem. - You **always** need a base case (the stop condition) and a recursive case that shrinks toward it. - The base case must actually be reachable for every valid input. - Recursion shines on **self-similar** structures (trees, nested data) and divide-and-conquer algorithms. - A missing/unreachable base case produces infinite recursion and a `StackOverflowError` at runtime.

  • What happens at runtime if the base case is never reached?
    The recursive calls never return, stack frames accumulate until the call stack is exhausted, and the JVM throws StackOverflowError.
  • Can any recursion be rewritten as a loop?
    Yes. Any recursive algorithm has an equivalent iterative form, sometimes by using an explicit stack data structure to replace the call stack.

saying these in an interview costs you the question

  • Claiming recursion can run forever safely without crashing
  • Forgetting that the recursive case must move toward the base case (having a base case alone is not enough)
  • Confusing the base case with the recursive case
  • Saying recursion is always better/cleaner than a loop

context

open as a page

Why does deep recursion in Java cause a StackOverflowError, and what controls how deep you can recurse?

level: middleimportance: must knowfreq 72%

basics

~20 s

Each method call uses a chunk of stack memory (a frame). The thread stack has a fixed limited size. Too many nested recursive calls fill it up, and the JVM throws StackOverflowError. How deep you can go depends on the stack size and how much each frame uses.

open as a page

Trace what this recursive method computes and identify any termination problem; how would you reason about a recursive method's correctness?

level: juniorimportance: should knowfreq 55%

basics

~20 s

To trace recursion, substitute the call by hand: replace each call with its body until you reach the base case, then combine the results on the way back. To check correctness, make sure the base case returns the right answer and that every recursive call moves the input closer to the base case.

open as a page

When would you choose recursion over iteration in Java, and what are the trade-offs?

level: middleimportance: should knowfreq 60%

basics

~20 s

Recursion is great when the data or problem is self-similar, like trees or nested structures, because the code mirrors the structure and is short and clear. Iteration with a loop uses constant stack space and is faster, so it is safer for deep or large inputs. Pick recursion for clarity on shaped data, iteration for depth and performance.

open as a page

Does the JVM optimize tail-recursive methods, and what are the consequences for writing recursive Java code?

level: seniorimportance: should knowfreq 58%

basics

~20 s

No. A tail call is a recursive call that is the very last thing a method does. Some languages reuse the same stack frame for it so it never overflows, but standard Java does not. So even tail-recursive Java methods add a frame per call and can still throw StackOverflowError on deep input.

open as a page