Java: как избежать StackOverflowException

Я пишу функцию, которая будет называть себя примерно до 5000 раз. Конечно, я получаю исключение StackOverflowException. Есть ли способ, чтобы я мог переписать этот код довольно простым способом:

void checkBlocks(Block b, int amm) {

    //Stuff that might issue a return call

    Block blockDown = (Block) b.getRelative(BlockFace.DOWN);
    if (condition) 
        checkBlocks(blockDown, amm);


    Block blockUp = (Block) b.getRelative(BlockFace.UP);
    if (condition) 
        checkBlocks(blockUp, amm);

    //Same code 4 more times for each side

}

Кстати, каково ограничение того, насколько глубоко мы можем назвать функции?

Спасибо!

Ответы

Ответ 1

Возможно использование стека?

void checkBlocks(Block b, int amm) {
  Stack<Block> blocks = new Stack<Block>();
  blocks.push(b);
  while (!blocks.isEmpty()) {
    b = blocks.pop();
    Block blockDown = (Block) b.getRelative(BlockFace.DOWN);
    if (condition)
      blocks.push(block);
    Block blockUp = (Block) b.getRelative(BlockFace.UP);
    if (condition) 
      blocks.push(block);
  }
}

Ответ 2

размер стека по умолчанию в java равен 512kb. если вы превысите эту программу, прекратите метать StackOverflowException

вы можете увеличить размер стека, передав аргумент JVM: -Xss1024k

теперь размер стека равен 1024kb. вы можете дать более высокое значение на основе вашей среды

Я не думаю, что мы можем программно изменить это

Ответ 3

Размер стека можно увеличить с помощью -Xss4m.

Ответ 4

Вы можете поместить свой "Блок" в очередь/стек и итерации до тех пор, пока доступны блоки.

Ответ 5

Очевидно, что вы получаете StackOverflow с таким коэффициентом ветвления вашей рекурсии. На других языках можно достичь с помощью оптимизации Tail Call Optimization. Но я полагаю, что ваша проблема нуждается в другом способе решения.

В идеале вы выполняете некоторую проверку блока. Может быть, вы можете получить список всех блоков и проверить каждый из них итеративно?

Ответ 6

В большинстве случаев рекурсия используется неверно. Вы не должны получать исключение стека за потоком. У вашего метода нет возвращаемого типа/значения. Как вы гарантируете, что ваш начальный блок b действителен?

Если вы используете рекурсию, задайте себе следующий вопрос:

  • Что такое мой рекурсивный якорь (когда я останавливаюсь с рекурсией)
  • Что такое мой шаг рекурсии (как уменьшить количество вычислений)

Пример:

  • п! = > n * n-1!

мой рекурсивный якорь равен n == 2 (результат равен 2), поэтому я могу рассчитать все результаты, начинающиеся с этого якоря.

мой шаг рекурсии n-1 (так что каждый шаг я приближаюсь к решению (и в этом случае к моему рекурсивному якорю))