You can convert your recursive algorithm to iterative, which will not cause a stack overflow. You can read in this answer . Recursion from your example in an iterative form:
public double calculate(long n) { double sum = 0; if (n <= 0) return sum; while (n > 0) { sum += f.apply((double) n); n--; } return sum; }
UPD # 1
As for your question directly, in the comments you yourself gave the correct answer. The tail recursion will look like this:
public double calculate(long n) { return calculate(n, 0); } public double calculate(long n, double sum) { return n <= 0 ? sum: calculate(n - 1, sum + f.apply((double) n)); }
I wrapped it in an overridden method so as not to change the code where the single-parameter method is used. Thus, when a program enters the else branch (of a ternary operator) again and again, we no longer need the actual stack — the program has everything it needs as arguments to the method in a recursive call.
UPD # 2
Indeed, as practice has shown, in Java 1.8 there is no tail recursion optimization (TRO). During the execution of the code, the stack is still expanded. I thought it might be possible to solve this issue using lambda functions, but failed and from now on we all plunge into the world of magic template functions =) Let's use the design jump pattern for jumping , which will convert stack-dependent recursion into the corresponding iterative algorithm. Since the cycles do not cause a stack descent, this can be considered as a form of chainless recursion. Here is the code to check:
import java.lang.Math; import java.util.Optional; import java.util.function.Function; class Trampoline<T> { public T getValue() { throw new RuntimeException("Not implemented"); } public Optional<Trampoline<T>> nextTrampoline() { return Optional.empty(); } public final T compute() { Trampoline<T> trampoline = this; while (trampoline.nextTrampoline().isPresent()) { trampoline = trampoline.nextTrampoline().get(); } return trampoline.getValue(); } } final class StacklessRecursiveFunction { public static Trampoline<Double> createTrampoline(final double n, final double sum) { if (n <= 0) { return new Trampoline<Double>() { public Double getValue() { return sum; } }; } return new Trampoline<Double>() { public Optional<Trampoline<Double>> nextTrampoline() { return Optional.of(createTrampoline(n - 1, sum + Math.pow(n + 1, n + 0.1) / n)); } }; } } class MagicStacklessRecur{ public static void main(String[] args) { System.out.println(StacklessRecursiveFunction.createTrampoline(Math.pow(10,1000), 0).compute()); } }
f, what is it generally needed for, and what really bothers you: a non-working code or tail recursion? - Regentjavaable to tail recursion? - Alexey Shimansky