Expert explanation: Easy to improve the performance of Java code

Source: Internet
Author: User
Tags contains integer variables variable
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.



Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.