Performance
tail-recursive conversions can speed up the application, but not all jvms do this conversion, Many algorithms use the tail-recursion method to express themselves to be particularly concise. The compiler automatically converts this method into a loop to improve the performance of the program. In the Java language Specification, however, there is no requirement to make this transition, so not all Java virtual machines (JVMS) do this. This means that the use of tail-recursive representations in the Java language can result in huge memory footprint, which is not what we expect. Eric Allen explains in this article that dynamic compilation will preserve the semantics of the language, while static compilation is not usually. He explains why this is an important issue and provides a piece of code to help you determine whether your Just-in-time (JIT) compiler will be able to do tail-recursive code conversion while maintaining language semantics.
Tail recursion and its transformation
Quite a few programs contain loops, which account for a large portion of the total running time of the program. These loops often have to update more than one variable, and each variable's update often relies on the value of other variables.
If the iteration is considered to be the tail recursive function, then these variables can be considered as parameters of the function. A simple reminder: If the return value of a call is returned immediately as the value of the calling function, then the recursive call is the tail recursion; tail recursion does not have to remember the context in which the function is invoked when invoked.
Because of this feature, there is a good correspondence between the tail recursive function and the loop: each recursive call can be considered simply as a multiple iteration of a loop. However, because all variable parameter values are passed to the recursive call at once, it is easier to get updated values in tail recursion than in the loop. Also, a break statement that is difficult to use is often substituted for the simple return of a function.
However, in Java programming, it is inefficient to represent iterations in this way, because a large number of recursive calls are at risk of causing a stack overflow.
The solution is simple: because the tail recursive function is actually just a simpler way to write loops, let the compiler automatically convert them to a circular form. This allows you to take advantage of both forms.
However, while everyone knows how to automatically convert a tail recursive function into a simple loop, the Java specification does not require this conversion. The reason for not doing this is probably this: typically in object-oriented languages, this conversion cannot be done statically. Conversely, this conversion from the tail recursive function to a simple loop must be performed dynamically by the JIT compiler.
To understand why this is the case, consider one of the following failed attempts: On the integers set, multiply the elements in the iterator.
Because there is an error in the following program, an exception is thrown at run time. But, as already argued in many of the previous articles in this column, the exact exception thrown by a program (as well as a great error type identifier) is not helpful in finding where the error is hidden in the program, and we do not want the compiler to alter the program in this way so that the compiled result code throws a different exception.   
list 1. a set of Integer Failed attempts to multiply elements in Iterator
IMPORT JAVA.UTIL.ITERATOR; 
Public class example  {&NBSP
public int product (iterator i) {
return producthelp (i, 0);
}
int Producthelp (Iterator i, int accumulator) {
if ( I.hasnext ()) {
return producthelp (i, accumulator * ((Integer) I.next ()). Intvalue ();
}
 ELSE {&NBSP
return accumulator;
  }&NBSP
}
}
Note the error in the product method. The product method calls Producthelp by assigning the accumulator to 0. It should have a value of 1. Otherwise, calling product on any instance of the class Example produces a value of 0, regardless of iterator value.
Suppose this error is finally corrected, but at the same time a subclass of class Example is created, as shown in Listing 2:
List 2. attempt to capture an incorrect call like Listing 1
Import java.util.*;
Class Example {
public int product (iterator i) {
Return Producthelp (i, 1);
}
int Producthelp (iterator i, int accumulator) {
if (I.hasnext ()) {
Return Producthelp (i, Accumulator * ((Integer) I.next ()). Intvalue ());
}
else {
return accumulator;
}
}
}
And, in a separate file:
Import java.util.*;
public class Example2 extends Example {
int Producthelp (iterator i, int accumulator) {
if (Accumulator < 1) {
throw new RuntimeException ("accumulator to Producthelp must is >= 1");
}
else {
Return Super.producthelp (i, accumulator);
}
}
public static void Main (string[] args) {
LinkedList L = new LinkedList ();
L.add (new Integer (0));
New Example2 (). Product (L.listiterator ());
}
}
The overridden productHelp method in class Example2 attempts to pass when accumulator is less than "1" Throws a Run-time exception to catch an incorrect call to productHelp . Unfortunately, this will introduce a new error. If Iterator contains an instance of any 0 value, the productHelp crashes on its own recursive invocation.
Now notice that in the main method of class Example2 , you create a example2 An instance of and its product method is invoked. Because the Iterator passed to this method contains a 0, the program crashes.
However, you can see that the productHelp of the class Example is strictly tail-recursive. Suppose a static compiler wants to convert the body of this method into a loop, as shown in Listing 3 : &NBSP;&NBSP;
list 3. Static compilation does not optimize an example of a tail call
int Producthelp (iterator i, int accumulator) {
while (I.hasnext ()) {
Accumulator *= ((Integer) I.next ()). Intvalue ();
}
return accumulator;
}
So, the initial call to Producthelp, the result is a call to the superclass method. The Super method calculates the result by simply looping through the iterator. Does not throw any exceptions.
Compiling this code with two different static compilers results in one that throws an exception and the other does not, and think about how confusing that is.