Think of a for loop as a little anonymous function that takes the loop index value as a parameter. In order to start the next iteration of the loop, the function can return a call to itself with a new value for the loop index parameter.

Like this:

Object loop(int i, Object data) {
    if (i > 0) {
        return loop(i - 1, evolve(data));
    } else {
        return data;
    }
}

That's the same as this:

for ( ; i > 0; i--) {
    data = evolve(data);
}

In some languages, particularly Scheme, and who knows maybe Java 8 or 9, the compiler is guaranteed to compile a recursive function such as the function loop above just the same as it compiles the for loop above.

In other languages, including the current and past versions of Java, nearly all compilers will make an executable that builds a big call stack. When the call stack is large it may even overflow the permitted size and crash the program.

Answer from minopret on Stack Overflow
🌐
W3Schools
w3schools.com β€Ί java β€Ί java_recursion.asp
Java Recursion
Just as loops can run into the problem of infinite looping, recursive methods can run into the problem of infinite recursion. Infinite recursion is when the method never stops calling itself.
Top answer
1 of 2
2

Think of a for loop as a little anonymous function that takes the loop index value as a parameter. In order to start the next iteration of the loop, the function can return a call to itself with a new value for the loop index parameter.

Like this:

Object loop(int i, Object data) {
    if (i > 0) {
        return loop(i - 1, evolve(data));
    } else {
        return data;
    }
}

That's the same as this:

for ( ; i > 0; i--) {
    data = evolve(data);
}

In some languages, particularly Scheme, and who knows maybe Java 8 or 9, the compiler is guaranteed to compile a recursive function such as the function loop above just the same as it compiles the for loop above.

In other languages, including the current and past versions of Java, nearly all compilers will make an executable that builds a big call stack. When the call stack is large it may even overflow the permitted size and crash the program.

2 of 2
2

Haters aside, let's do this! [1]

Given:

int x = 3;
for (int i = 0; i < x; i++) {
  for (int j = 0; j < x; j++) {
    for (int k = 0; k < x; k++){
      list.add(array[i] + array[j] + array[k]);
    }
  }
}

Let's consider that each loop is it's own recursive function - as this makes the recurrence cases much easier! This is also the only "non-thinking" method I know of to turn the loops into recursion. The recursive depth will be limited to 3*x => i+j+k so it's "fairly safe" for a smallish[2] x.

In Java it requires a separate method for each loop to encode this structure. (In a language with higher-order functions these three functions might be abstractly combined .. but not in Java [7].)

void loopI(int i) {
    if (i < x) {
      loopJ(0);   // "start j loop"
      loopI(i++); // "next i loop" / recurrence case
    }
    // "end loop" / base case
}

void loopJ(int j) {
    if (j < x) {
      loopK(0);
      loopJ(j++);
    }
}

void loopK(int k) {
   if (k < x) {
     list.add(array[i] + array[j] + array[k]);
     loopK(k++);
   }
}

// do it!
loopI(0); 

All of these could be combined into a single recursive function, but that makes handling the recurrence cases a bit tougher as "thinking" and additional conditionals (or mod expressions, perhaps) are required to advance the state.

Here is an example of a combined recursive function (this is incorrect when x is 0). Unlike the three method approach above, the stack depth will grow to x^3 => i*j*k. This will easily kill Java's recursion limits - even for smallish values of x- as Java [7] doesn't have tail-call optimization.

void loop(int i, int j, int k) {        
    list.add(array[i] + array[j] + array[k]);

    // advance states
    k++;
    if (k == x) { k = 0; j++; }
    if (j == x) { j = 0; i++; }
    if (i == x) { i = 0; }

    // terminate on all wrap-around
    if (i == 0 && j == 0 && k == 0) { return; }

    // recurse
    loop(i, j, k);
}

[1] YMMV, for theoretical purposes only - I love recursion, but it's not suited for this case in Java.

[2] For some value of "smallish". See how deep your stack can go!

🌐
Coderanch
coderanch.com β€Ί t β€Ί 629435 β€Ί java β€Ί recursion-loop-works
how recursion inside for loop works (Java in General forum at Coderanch)
February 25, 2014 - programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums Β· this forum made possible by our volunteer staff, including ... ... can you guys tell me hoe this recursion print 3 2 1 2 1 3 2 1 2 1 3 2 1 2 1 if i call it with value 3.
Top answer
1 of 2
49

Actually you should break the function down first:

A loop has a few parts:

  1. the header, and processing before the loop. May declare some new variables

  2. the condition, when to stop the loop.

  3. the actual loop body. It changes some of the header's variables and/or the parameters passed in.

  4. the tail; what happens after the loop and return result.

Or to write it out:

foo_iterative(params){
    header
    while(condition){
        loop_body
    }
    return tail
}

Using these blocks to make a recursive call is pretty straightforward:

foo_recursive(params){
    header
    return foo_recursion(params, header_vars)
}

foo_recursion(params, header_vars){
    if(!condition){
        return tail
    }

    loop_body
    return foo_recursion(params, modified_header_vars)
}

Et voilΓ ; a tail recursive version of any loop. breaks and continues in the loop body will still have to be replaced with return tail and return foo_recursion(params, modified_header_vars) as needed but that is simple enough.


Going the other way is more complicated; in part because there can be multiple recursive calls. This means that each time we pop a stack frame there can be multiple places where we need to continue. Also there may be variables that we need to save across the recursive call and the original parameters of the call.

We can use a switch to work around that:

bar_recurse(params){
    if(baseCase){
        finalize
        return
    }
    body1
    bar_recurse(mod_params)
    body2
    bar_recurse(mod_params)
    body3
}


bar_iterative(params){
    stack.push({init, params})

    while(!stack.empty){
        stackFrame = stack.pop()

        switch(stackFrame.resumPoint){
        case init:
            if(baseCase){
                finalize
                break;
            }
            body1
            stack.push({resum1, params, variables})
            stack.push({init, modified_params})
            break;
        case resum1:
            body2
            stack.push({resum2, params, variables})
            stack.push({init, modified_params})
            break;
        case resum2:
            body3
            break;
        }
    }
}
2 of 2
2

Following up on @ratchet freak's answer, I created this example of how the Fibonacci function can be rewritten to a while loop in Java. Note that There's a much simpler (and efficient) way to rewrite the Fibonacci with a while loop though.

class CallContext { //this class is similar to the stack frame

    Object[] args;

    List<Object> vars = new LinkedList<>();

    int resumePoint = 0;

    public CallContext(Object[] args) {
        this.args = args;
    }

}


static int fibonacci(int fibNumber) {
    Deque<CallContext> callStack = new LinkedList<>();
    callStack.add(new CallContext(new Object[]{fibNumber}));
    Object lastReturn = null; //value of last object returned (when stack frame was dropped)
    while (!callStack.isEmpty()) {
        CallContext callContext = callStack.peekLast();
        Object[] args = callContext.args;
        //actual logic starts here
        int arg = (int) args[0];
        if (arg == 0 || arg == 1) {
            lastReturn = arg;
            callStack.removeLast();
        } else {
            switch (callContext.resumePoint) {
                case 0: //calculate fib(n-1)
                    callStack.add(new CallContext(new Object[]{arg - 1}));
                    callContext.resumePoint++;
                    break;
                case 1: //calculate fib(n-2)
                    callContext.vars.add(lastReturn); //fib1
                    callStack.add(new CallContext(new Object[]{arg - 2}));
                    callContext.resumePoint++;
                    break;
                case 2: // fib(n-1) + fib(n-2)
                    callContext.vars.add(lastReturn); //fib2
                    lastReturn = (int) callContext.vars.get(0) + (int) callContext.vars.get(1);
                    callStack.removeLast();
                    break;
            }
        }
    }
    return (int) lastReturn;
}
🌐
Study.com
study.com β€Ί computer science courses β€Ί computer science 201: data structures & algorithms
Methods for Recursion vs. Iteration in Java - Lesson | Study.com
April 23, 2021 - Recursion is a Java function that calls itself, while iteration loops through the code block. Both techniques are similar in that they have start points, exit points, and sequence through code repetitively.
🌐
Programiz
programiz.com β€Ί java-programming β€Ί recursion
Java Recursion: Recursive Methods (With Examples)
When a recursive call is made, new storage locations for variables are allocated on the stack. As, each recursive call returns, the old variables and parameters are removed from the stack. Hence, recursion generally uses more memory and is generally slow. On the other hand, a recursive solution is much simpler and takes less time to write, debug and maintain. ... Before we wrap up, let’s put your knowledge of Java Recursion to the test!
🌐
Princeton CS
introcs.cs.princeton.edu β€Ί java β€Ί 23recursion
Recursion
May 24, 2020 - The function-call mechanism in Java supports this possibility, which is known as recursion. The "Hello, World" for recursion is the factorial function, which is defined for positive integers n by the equation Β· $$n! = n \times (n-1) \times (n-2) \times \; \ldots \; \times 2 \times 1$$ The quantity n! is easy to compute with a for loop...
Find elsewhere
🌐
Quora
quora.com β€Ί How-does-recursion-work-inside-a-for-loop-Most-importantly-how-does-it-flow
How does recursion work inside a for loop? Most importantly, how does it flow? - Quora
Answer (1 of 5): Recursion IS NOT a simple thing to master. The idea is very simple, which is a function that can call itself. E.g ( fibonacci ) : A very simple code to count rabbits… anyways, the idea of recursion is to get a big problem ( what is the fibonacci of 5 ? ), and break it down into ...
🌐
GeeksforGeeks
geeksforgeeks.org β€Ί java β€Ί recursion-in-java
Recursion in Java - GeeksforGeeks
July 11, 2025 - A recursive function calls itself, the memory for the called function is allocated on top of memory allocated to the calling function and a different copy of local variables is created for each function call. When the base case is reached, the function returns its value to the function by whom it is called and memory is de-allocated and the process continues. Let us take the example of recursion by taking a simple function. ... // A Java program to demonstrate // working of recursion class GFG { static void printFun(int test) { if (test < 1) return; else { System.out.printf("%d ", test); // Statement 2 printFun(test - 1); System.out.printf("%d ", test); return; } } public static void main(String[] args) { int test = 3; printFun(test); } }
🌐
Stack Overflow
stackoverflow.com β€Ί questions β€Ί 53122414 β€Ί recursion-using-for-loop
java - Recursion using for-loop - Stack Overflow
public class Calc { public static void main(String[] args) { Scanner sc = new Scanner(System.in); double k = sc.nextDouble(); double e = sc.nextDouble(); double q = sc.nextDouble(); int n = sc.nextInt(); for (int i = 0; i < n; i++) { k = (k + (i * e)) * (1 + q); //The problem I have is that I don't know how to access the previous element of the for-loop } } } ... You say you should recursion, but I don't see any method that could be called recursively.
🌐
Baeldung
baeldung.com β€Ί home β€Ί java β€Ί core java β€Ί recursion in java
Recursion in Java | Baeldung
January 2, 2026 - In Java, the function-call mechanism supports the possibility of having a method call itself. This functionality is known as recursion. For example, suppose we want to sum the integers from 0 to some value n:
Top answer
1 of 8
44

You misunderstood recursion: although it can be used to replace iteration, there is absolutely no requirement for the recursive function not to have iterations internal to itself.

The only requirement for a function to be considered recursive is the existence of a code path through which it calls itself, directly or indirectly. All correct recursive functions also have a conditional of some sort, preventing them from "recursing down" forever.

Your recursive function is ideal to illustrate the structure of recursive search with backtracking. It starts with the check of the exit condition row < n, and proceeds to making search decisions on its level of recursion (i.e. picking a possible position for queen number row). After each iteration, a recursive call is made to build upon the configuration that the function has found so far; eventually, it "bottoms out" when row reaches n in the recursive call that is n levels deep.

2 of 8
12

The general structure of a recursive function is something like this:

myRecursiveFunction(inputValue)
begin
   if evaluateBaseCaseCondition(inputValue)=true then
       return baseCaseValue;
   else
       /*
       Recursive processing
       */
       recursiveResult = myRecursiveFunction(nextRecursiveValue); //nextRecursiveValue could be as simple as inputValue-1
       return recursiveResult;
   end if
end

The text that I marked as /*recursive processing*/ could be anything. It could include a loop, if the problem being solved requires it, and could also include recursive calls to myRecursiveFunction.

🌐
Jct
danzig.jct.ac.il β€Ί java_class β€Ί recursion.html
Java Recursion with examples
When do we prefer recursion to an iterative loop? We use recursion when we can see that our problem can be reduced to a simpler problem that can be solved after further reduction. Every recursion should have the following characteristics. A simple base case which we have a solution for and ...
🌐
Software Testing Help
softwaretestinghelp.com β€Ί home β€Ί java β€Ί recursion in java – tutorial with examples
Recursion In Java - Tutorial With Examples
April 1, 2025 - It also covers Recursion Vs Iteration: From our earlier tutorials in Java, we have seen the iterative approach wherein we declare a loop and then traverse through a data structure in an iterative manner by taking one element at a time. We have also seen the conditional flow where again we keep one loop variable and repeat a piece of code till the loop variable meets the condition. When it comes to function calls, we explored the iterative approach for ...
Top answer
1 of 2
2

Your problem is not in the part you posted.

I added dummy implementations for all the classes and methods used in your method, and it runs quite fine, stopping at level 6.

package de.fencing_game.paul.examples;

import java.util.*;

public class RecursionAndLoop {


    private static class Move {
        private String id;
        public Move(String type) {
            this.id = type;
        }
        public String toString(){
            return "Move(" + id + ")";
        }

    }


    private static class GameState {
        private static int nextID;

        private int id;

        GameState() {
            this.id = nextID++;
        }

        public GameState getNewInstance(Move move) {
            return new GameState();
        }

        public int getPossibleMoveCount(int index) {
            return 5;
        }

        public Vector<Move> getPossibleMoves(int index) {
            Vector<Move> v = new Vector<Move>();
            for(int i = 0; i < 5; i++) {
                v.add(new Move(index + "Γ—" + i));
            }
            return v;
        }

        public int getMarkCount(int index) {
            return 20 + index;
        }

        public String toString() {
            return "GameState[" + id + "]";
        }
    }

    private static class Node {
        private GameState state;
        private Move move;

        private List<Node> children;
        private Node parent;
        private int score;

        public Node(GameState s, Move m) {
            this.children = new ArrayList<Node>();
            this.state = s;
            this.move = m;
        }

        public void addChild(Node child) {
            children.add(child);
        }

        public void setParent(Node node) {
            parent = node;
        }

        public void setScore(int neu) {
            this.score = neu;
        }

        public int getDepth() {
            if(parent == null) {
                return 0;
            }
            return 1 + parent.getDepth();
        }

        /**
         * prints a simple tree view of this ZipNode and its descendants
         * on {@link System.out}.
         * @param prefix a prefix string to add before all lines.
         * @param self a prefix string to add before the line of this node
         *    itself (after the general prefix).
         * @param sub a prefix string to add before the line of all subnodes
         *    of this node (after the general prefix).
         */
        private void printTree(String prefix,
                               String self,
                               String sub) {
            System.out.println(prefix + self + state + " - " + move +
                               " - " + score);
            String subPrefix = prefix + sub;
            // the prefix strings for the next level.
            String nextSelf = " β”œβ”€ ";
            String nextSub =  " β”‚ ";
            Iterator<Node> iterator =
                this.children.iterator();
            while(iterator.hasNext()) {
                Node child = iterator.next();
                if(!iterator.hasNext() ) {
                    // last item, without the "|"
                    nextSelf = " └─ ";
                    nextSub =  "   ";
                }
                child.printTree(subPrefix, nextSelf, nextSub);
            }
        }



    }


    int switchIndex(int index) {
        return index + 1;
    }



    private void makeTree(GameState prevState, Vector<Move> moves, Node parentNode, int index, int depthLimit) {

        if(prevState.getPossibleMoveCount(index) != 0){

            for(int i = 0; i < moves.size(); i++){

                Move thisMove = moves.get(i);
                GameState newState = prevState.getNewInstance(thisMove);
                Node child = new Node(newState, thisMove);
                parentNode.addChild(child);
                child.setParent(parentNode);

                if((child.getDepth() + 1) < depthLimit){

                    int newIndex = switchIndex(index);
                    Vector<Move> newMoves = newState.getPossibleMoves(newIndex);
                    makeTree(newState, newMoves, child, newIndex, depthLimit);

                }else{

                    child.setScore(newState.getMarkCount(index));
                }
            }
        }
    }


    public static void main(String[] params) {
        GameState start = new GameState();
        Vector<Move> m = new Vector<Move>();
        m.add(new Move("start"));
        Node root = new Node(start, null);
        int index = 7;
        int depthLimit = 6;
        new RecursionAndLoop().makeTree(start, m, root, index, depthLimit);
        root.printTree("", " ", "");
    }

}

(I changed a bit to generic types to avoid compiler warnings.)

Here is the output for depthLimit=4:

GameState[0] - null - 0
└─ GameState[1] - Move(start) - 0
   β”œβ”€ GameState[2] - Move(8Γ—0) - 0
   β”‚  β”œβ”€ GameState[3] - Move(9Γ—0) - 29
   β”‚  β”œβ”€ GameState[4] - Move(9Γ—1) - 29
   β”‚  β”œβ”€ GameState[5] - Move(9Γ—2) - 29
   β”‚  β”œβ”€ GameState[6] - Move(9Γ—3) - 29
   β”‚  └─ GameState[7] - Move(9Γ—4) - 29
   β”œβ”€ GameState[8] - Move(8Γ—1) - 0
   β”‚  β”œβ”€ GameState[9] - Move(9Γ—0) - 29
   β”‚  β”œβ”€ GameState[10] - Move(9Γ—1) - 29
   β”‚  β”œβ”€ GameState[11] - Move(9Γ—2) - 29
   β”‚  β”œβ”€ GameState[12] - Move(9Γ—3) - 29
   β”‚  └─ GameState[13] - Move(9Γ—4) - 29
   β”œβ”€ GameState[14] - Move(8Γ—2) - 0
   β”‚  β”œβ”€ GameState[15] - Move(9Γ—0) - 29
   β”‚  β”œβ”€ GameState[16] - Move(9Γ—1) - 29
   β”‚  β”œβ”€ GameState[17] - Move(9Γ—2) - 29
   β”‚  β”œβ”€ GameState[18] - Move(9Γ—3) - 29
   β”‚  └─ GameState[19] - Move(9Γ—4) - 29
   β”œβ”€ GameState[20] - Move(8Γ—3) - 0
   β”‚  β”œβ”€ GameState[21] - Move(9Γ—0) - 29
   β”‚  β”œβ”€ GameState[22] - Move(9Γ—1) - 29
   β”‚  β”œβ”€ GameState[23] - Move(9Γ—2) - 29
   β”‚  β”œβ”€ GameState[24] - Move(9Γ—3) - 29
   β”‚  └─ GameState[25] - Move(9Γ—4) - 29
   └─ GameState[26] - Move(8Γ—4) - 0
      β”œβ”€ GameState[27] - Move(9Γ—0) - 29
      β”œβ”€ GameState[28] - Move(9Γ—1) - 29
      β”œβ”€ GameState[29] - Move(9Γ—2) - 29
      β”œβ”€ GameState[30] - Move(9Γ—3) - 29
      └─ GameState[31] - Move(9Γ—4) - 29
2 of 2
0

When you call

makeTree(newState, newMoves, child, newIndex, depth);

inside of your if statement where are you expecting depth to come from? It looks like you're passing in depth to the makeTree routine, yet expecting it to be the depth of the current node (this.depth maybe?)

🌐
Refactoring
refactoring.com β€Ί catalog β€Ί replaceRecursionWithIteration.html
Replace Recursion with Iteration - Refactoring
Every Recursion must have a defined base case. In addition, each recursive call must make a progress towards the base case (otherwise recursive calls would be performed infinitely). In our example the base case is n == 0. Implement a loop that will iterate until the base case is reached.
🌐
MakeUseOf
makeuseof.com β€Ί home β€Ί programming β€Ί what is a recursive function, and how do you create one in java?
What Is a Recursive Function, and How Do You Create One in Java?
April 12, 2021 - The variable β€œn” will be assigned a random number from the user and the β€œcount” variable will increase by one each time a loop is performed, but as soon as the value of the β€œcount” variable exceeds that of β€œn” then the loop will stop. If we were to examine the facts surrounding iteration and recursion, we will find several things to be true. Both methods involve repetition. Both methods require a test condition, which will indicate when to stop. Both methods can theoretically execute forever if an exit condition isn’t given or met.