A summary of programming techniques for Java performance optimization

Source: Internet
Author: User
Tags arithmetic bitwise instance method shallow copy

The performance of the program is directly affected by the quality of the code. In this article, I'll focus on some code-writing tips and conventions that can help you improve system performance at the code level.

1, cautious use of abnormal

In Java software development, Try-catch are often used for error trapping, but Try-catch statements are very bad for system performance. While it is not possible to detect the loss of performance in a single try-catch, once the try-catch is applied to the loop, it can cause great damage to the system.

The following is an example of applying try-catch to A for loop

   public void test() {        int a = 0;        for (int i = 0; i < 1000000; i++) {            try {                a = a + 1;                System.out.println(i);            } catch (Exception e) {                e.printStackTrace();            }        }    }

This piece of code I run time is 27211 Ms. If the Try-catch is moved outside the loop body, then the system performance can be improved, the following code

    public void test() {        int a = 0;        try {            for (int i = 0; i < 1000000; i++) {                a = a + 1;                System.out.println(i);            }        } catch (Exception e) {            e.printStackTrace();        }    }

Run time 15647 Ms. The effect of Tyr-catch on system performance is visible.

2. Use local environment

The parameters passed when the method is called and the temporary variables created in the call are saved in the stack, which is faster. Other variables, such as static variables, instance variables, and so on, are created in the heap and are slower.

Here is a test case

//   private static int a = 0;    public static void main(String[] args) {        int a = 0;        long start = System.currentTimeMillis();        for (int i = 0; i < 1000000; i++) {            a = a + 1;            System.out.println(i);        }        System.out.println(System.currentTimeMillis() - start);    }

The running result is obvious, using a static variable takes 15677ms, and using a local variable takes 13509ms of time. Thus, local variables are accessed faster than member variables of the class .

3, bit operation instead of multiplication method

In all operations, bit operations are the most efficient . Therefore, you can try to improve the speed of the system by using bit operations instead of some arithmetic operations.

For example, the use of bit arithmetic in the source code of HashMap

    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16    static final int MAXIMUM_CAPACITY = 1 << 30;

Optimization of multiplication operations for integers

a*=2a/=2

The bitwise operation can be written as

a<<=1a>>=1
4. Replace switch

The keyword switch statement is used for multi-conditional judgments, and the switch statement functions similarly to the IF-ELSE statement, and the performance is similar. Therefore, you cannot say that the switch statement degrades the performance of the system. However, in most cases, the switch statement has a performance-enhancing space.

Take a look at the following example:

    public static void main(String[] args) {        long start = System.currentTimeMillis();        int re = 0;        for (int i = 0;i<1000000;i++){            re = switchInt(i);            System.out.println(re);        }        System.out.println(System.currentTimeMillis() - start+"毫秒");//17860    }    public static int switchInt(int z){        int i = z%10+1;        switch (i){            case 1:return 3;            case 2:return 6;            case 3:return 7;            case 4:return 8;            case 5:return 10;            case 6:return 16;            case 7:return 18;            case 8:return 44;            default:return -1;        }    }

In terms of branching logic, this switch mode is not performing poorly. However, if you replace switch with a new idea, and realize the same program function, there will be a lot of room for improvement in performance.

    public static void main(String[] args) {        long start = System.currentTimeMillis();        int re = 0;        int[] sw = new int[]{0,3,6,7,8,10,16,18,44};        for (int i = 0;i<1000000;i++){            re = arrayInt(sw,i);            System.out.println(re);        }        System.out.println(System.currentTimeMillis() - start+"毫秒");//12590    }        public static int arrayInt(int[] sw,int z){        int i = z%10+1;        if (i>7 || i<1){            return -1;        }else {            return sw[i];        }    }

The above code uses a new approach, using a sequential array instead of a switch statement. Because random access to data is very fast, at least better than the branch judgment of switch. Through experiments, using the switch statement takes 17860ms, and using the array implementation takes only 12590ms, which increases the number of 5s. In software development, a different approach may have better results, such as using arrays instead of switch statements is a good example.

5, one-dimensional arrays instead of two-dimensional arrays

Because of the very good performance of random access to arrays, many JDK class libraries, such as ArrayList, vectors, and so on, are implemented using arrays as their arrays. However, as a software developer, it is also important to know that the access speed of an array and a two-dimensional array is not the same. An array is accessed faster than a two-dimensional array . Therefore, in a performance-sensitive system to use a two-dimensional array, you can try the reliable algorithm, the two-dimensional array into a one-dimensional array and then processed to improve the system's response speed.

6. Extracting expressions

In the software development process, it is easy for programmers to inadvertently let the code do some "repetitive work", in most cases, because the computer tells the operation, these "repetitive work" does not pose too much of a threat to performance, but if the system to achieve the ultimate, extracting these "repetitive work" is quite meaningful.

Consider the following test cases:

    @Test    public void test(){        long start = System.currentTimeMillis();        ArrayList list = new ArrayList();        for (int i = 0;i<100000;i++){            System.out.println(list.add(i));        }        //以上是为了做准备        for (int i = 0;i<list.size();i++){            System.out.println(list.get(i));        }        System.out.println(System.currentTimeMillis() - start);//5444    }

If we extract the List.size () method, the optimized code is as follows:

    @Test    public void test(){        long start = System.currentTimeMillis();        ArrayList list = new ArrayList();        for (int i = 0;i<100000;i++){            System.out.println(list.add(i));        }        //以上是为了做准备        int n = list.size();        for (int i = 0;i<n;i++){            System.out.println(list.get(i));        }        System.out.println(System.currentTimeMillis() - start);//3514    }

On my machine, the former time-consuming 5444ms, the latter time-consuming 3514ms, the difference between 2s, visible, the extraction of repetitive operations is quite meaningful.

7. Expand Cycle

Slightly different from the optimization techniques described earlier, the author argues that the unwinding cycle is an optimization method used in extreme situations, because the expansion loops are likely to affect the readability and maintainability of the code, which is also extremely important for software systems. However, when the performance problem becomes the system principal contradiction, the unfolding cycle is definitely a technique worth trying.

8. Boolean operation instead of bitwise operation

Although bit operations are much faster than arithmetic operations, using bitwise operations instead of Boolean operations is a very bad choice when it comes to conditional judgment.

When the condition is judged, Java makes a fairly good optimization of the boolean operation. Assuming that there is an expression a,b,c the Boolean operation "A&&b&&c", according to the logic and characteristics, as long as there is an item in the entire Boolean expression return false, the entire expression will return false, so when the expression A is false, The expression returns false immediately, and no more expressions B and C are evaluated. Similarly, when the calculation expression is "a| | b| | C "is also the same.

If you use bitwise arithmetic (Bitwise AND "&", bitwise OR "|") Instead of logic and logic or, although bit arithmetic itself has no performance problems, bit operations always have to complete all the sub-expressions and then give the final result. Therefore, from this point of view, using bitwise operations instead of Boolean operations can make the system perform many invalid computations.

9. Using Arraycopy ()

Array replication is a highly used feature, and the JDK provides an efficient API to implement it:

If the application needs to replicate the array, this function should be used instead of its own implementation.

Method Code:

  public static native void arraycopy(Object src,  int  srcPos,                                        Object dest, int destPos,                                        int length);

Its usage is to copy the source array src from the index srcpos to the index destpos of the target array dest, and the length of the copy is long.

The System.arraycopy () method is the native method, and generally the performance of the native method is superior to the normal method. For performance reasons only, in software development, call the native method as much as possible.

10. I/O stream operation with buffer

In addition to NIO, there are two basic ways of using Java for I/O operations:

    1. Using InputStream and OutputStream-based methods; (Byte stream)
    2. Use Writer and Reader. (character stream)

Regardless of the way you use file I/O, if you can use buffering properly, you can effectively improve I/O performance.

11. Use Clone () instead of new

The most common way to create new object instances in Java is to use the New keyword. JDK support for new is very good, very fast when creating lightweight objects with the new keyword. However, for heavyweight objects, the execution time of the constructor may be longer because the object may perform some complex and time-consuming operations in the constructor. Causes the system to not get a large number of instances in the short term. To solve this problem, you can use the Object.clone () method.

The Object.clone () method can quickly replicate an object instance by bypassing the constructor. However, by default, the instance generated by the clone () method is only a shallow copy of the original object.

I have to mention that Java is only a value passed, I understand that the basic data type refers to the value, the ordinary object refers to the value, but the ordinary object refers to the value of an object is actually the address. code example:

  int i = 0;  int j = i;    //i的值是0  User user1 = new User();  User user2 = user1;   //user1值是new User()的内存地址

If deep copies are required, the clone () method needs to be re-implemented. Here's a look at the Clone () method implemented by ArrayList:

    public Object clone() {        try {            ArrayList<?> v = (ArrayList<?>) super.clone();            v.elementData = Arrays.copyOf(elementData, size);            v.modCount = 0;            return v;        } catch (CloneNotSupportedException e) {            // this shouldn't happen, since we are Cloneable            throw new InternalError(e);        }    }

In the Clone () method of ArrayList, first use the Super.clone () method to generate a shallow copy object. Then copy a new Elementdata array for the new ArrayList to refer to. Enables the cloned ArrayList object to hold a different reference to the original object, enabling a deep copy.

12. Static method Substitution instance method

The method described using the static keyword is a static method. In Java, because the instance method needs to maintain a structure similar to the virtual function table, the support for polymorphism is realized. The invocation of an instance method requires more resources than a static method. Therefore, for some commonly used tool class methods, there is no need to overload them, so declaring them as static can speed up the invocation of the method. Also, calling the static method does not require an instance of the generated class. is more convenient and easy to use than invoking instance methods.

Reference

Java Program Performance optimization (Ge Yi)

Before, I pursue the breadth of learning, now, I pursue the depth of learning!

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.