Inventory of 35 Java code optimization details

Inventory of 35 Java code optimization details



Code optimization is a very important subject. Some people may find it useless. What can be modified in some small areas? What impact does the modification have on the efficiency of the code? This is how I think about this question. Just like a whale in the ocean, is it useful to eat a small shrimp? It's useless, but after eating more shrimps, the whales are fed.

The same is true for code optimization. If the project focuses on going online as soon as possible without BUG, ​​then you can focus on the big ones and put down the small ones. The details of the code need not be carefully polished; but if there is enough time to develop and maintain the code, you must consider each one at this time. The details that can be optimized, the accumulation of small optimization points, will definitely improve the operating efficiency of the code.

The goals of code optimization are:

Reduce the size of the code

Improve the efficiency of code execution

Code optimization details

1. Try to specify the final modifier of the class and method

Classes with final modifiers are not derivable. In the Java core API, there are many examples of final applications, such as java.lang.String, the entire class is final. Specifying a final modifier for a class prevents the class from being inherited, and specifying a final modifier for a method prevents the method from being overridden. If a class is specified as final, all methods of that class are final. The Java compiler will look for opportunities to inline all final methods. Inlining plays a significant role in improving the efficiency of Java operations. For details, see Java runtime optimization. This can increase performance by an average of 50%.

2. Reuse objects as much as possible

Especially the use of String objects, StringBuilder/StringBuffer should be used instead when string connection occurs. Since the Java virtual machine not only takes time to generate objects, it may also take time to garbage collect and process these objects in the future. Therefore, generating too many objects will have a great impact on the performance of the program.

3. Use local variables as much as possible

The parameters passed when the method is called and the temporary variables created in the call are saved in the stack faster, and other variables, such as static variables, instance variables, etc., are created in the heap at a slower speed. In addition, the variables created in the stack are gone with the end of the method, and no additional garbage collection is required.

4. Close the stream in time

In the process of Java programming, you must be careful when performing database connections and I/O stream operations. After use, close them in time to release resources. Because the operation of these large objects will cause large system overhead, a little carelessness will lead to serious consequences.

5. Minimize the repeated calculation of variables

Clarify a concept, even if there is only one sentence in the method, it is costly to call a method, including creating a stack frame, protecting the scene when the method is called, and restoring the scene when the method is called. So for example the following operation:

It is recommended to replace it with:

In this way, when the list.size is large, it reduces a lot of consumption

6. Try to use a lazy loading strategy, that is, create when needed*


It is recommended to replace it with:

7. Use exceptions with caution

Anomalies are detrimental to performance. To throw an exception, first create a new object. The constructor of the Throwable interface calls the local synchronization method named fillInStackTrace. The fillInStackTrace method checks the stack and collects call trace information. As long as an exception is thrown, the Java virtual machine must adjust the call stack, because a new object is created during processing. Exceptions can only be used for error handling, and should not be used to control program flow.

[Image upload failed...(image-b49a00-1567085107360)]

8. Don't use try...catch... in the loop, it should be placed on the outermost layer

Except as a last resort. If you write this for no reason, as long as your leader is more senior and obsessive-compulsive, Bacheng will scold you for writing such garbage code.

9. If the length of the content to be added can be estimated, specify the initial length for the collection and tool classes implemented in an array at the bottom layer

Such as ArrayList, LinkedLlist, StringBuilder, StringBuffer, HashMap, HashSet, etc., take StringBuilder as an example:

(1) StringBuilder//16 characters are allocated by default

(2) StringBuilder(int size)//The default allocation of space for size characters

(3) StringBuilder(String str)//16 characters + str.length character space are allocated by default

The initial capacity can be set through the class (not only the StringBuilder above), which can significantly improve performance. Take StringBuilder, for example, length represents the number of characters that the current StringBuilder can hold. Because when the StringBuilder reaches its maximum capacity, it will increase its capacity to twice its current capacity and then add 2. Whenever StringBuilder reaches its maximum capacity, it has to create a new character array and then add the old characters Copy the contents of the array to the new character array-this is a very performance-consuming operation. Just imagine, if you can estimate that 5000 characters are stored in the character array without specifying the length, the second power of 5000 is 4096, regardless of the increase of 2 for each expansion, then:

(1) On the basis of 4096, apply for a character array of 8194 size, which is equivalent to applying for a character array of 12290 size at one time. If you can specify a character array of 5000 size at the beginning, the savings will be more than doubled Space;

(2) Copy the original 4096 characters to the new character array.

In this way, both memory space is wasted and the code operation efficiency is reduced. Therefore, it is not wrong to set a reasonable initial capacity for the collection and tool classes implemented by the array at the bottom, which will bring immediate results. Note, however, that a collection like HashMap is implemented as an array + linked list. Don't set the initial size to the same size as your estimated size, because the possibility of connecting only one object on a table is almost zero. The initial size is recommended to be set to the Nth power of 2. If it can be estimated that there are 2000 elements, it can be set to new HashMap (128) or new HashMap (256).

10. When copying large amounts of data, use the System.arraycopy command

11. Multiplication and division use shift operations


The shift operation can greatly improve the performance, because at the bottom of the computer, the alignment operation is the most convenient and fastest, so it is recommended to modify it to:

Although the shift operation is fast, it may make the code not easy to understand, so it is best to add corresponding comments.

12. Don't keep creating object references in the loop


This approach will result in count Object references in the memory. If the count is large, it will consume memory. It is recommended to change it to:

In this case, there is only one Object object reference in the memory, and each time a new Object is used, the Object object reference points to a different Object, but there is only one copy in the memory, which greatly saves memory space.

13. Based on efficiency and type checking considerations, array should be used as much as possible, and ArrayList should be used when the size of the array cannot be determined.

14. Try to use HashMap, ArrayList, StringBuilder, unless thread safety is required, it is not recommended to use Hashtable, Vector, StringBuffer, the latter three cause performance overhead due to the use of synchronization mechanisms

15. Don't declare the array as public static final

Because this is meaningless, it just defines the reference as static final, and the contents of the array can be changed at will. Declaring the array as public is even more a security hole, which means that the array can be changed by external classes.

16. Try to use singletons where appropriate

Using singletons can reduce the burden of loading, shorten loading time, and improve loading efficiency, but not all places are suitable for singletons. In simple terms, singletons are mainly suitable for the following three aspects:

(1) Control the use of resources, and control concurrent access to resources through thread synchronization

(2) Control the generation of instances to achieve the purpose of saving resources

(3) Control the sharing of data, and allow multiple unrelated processes or threads to communicate without establishing a direct association

17. Try to avoid random use of static variables

You know, when an object is referenced by a variable defined as static, gc usually does not reclaim the heap memory occupied by this object, such as:

At this time, the life cycle of static variable b is the same as that of class A. If class A is not unloaded, then the object B pointed to by reference B will stay in memory until the program terminates

18. Clear the sessions that are no longer needed in time

In order to clear sessions that are no longer active, many application servers have a default session timeout period, which is generally 30 minutes. When the application server needs to save more sessions, if the memory is insufficient, then the operating system will transfer part of the data to the disk, and the application server may also dump some inactive sessions to the disk according to the MRU (most frequently used recently) algorithm. It may even throw out of memory exceptions. If the session is to be dumped to disk, it must be serialized first. In a large-scale cluster, the cost of serializing objects is very expensive. Therefore, when the session is no longer needed, the invalidate method of HttpSession should be called to clear the session in time.

19. Collections that implement the RandomAccess interface, such as ArrayList, should use the most common for loop instead of the foreach loop to traverse

This is recommended by the JDK to users. The JDK API's interpretation of the RandomAccess interface is: the implementation of the RandomAccess interface is used to indicate that it supports fast random access. The main purpose of this interface is to allow general algorithms to change its behavior, so that it can provide good results when applied to random or continuous access lists. performance. Practical experience has shown that if the class instance that implements the RandomAccess interface is randomly accessed, the efficiency of using a normal for loop will be higher than that of using a foreach loop; conversely, if it is accessed sequentially, using Iterator will be more efficient. You can use code similar to the following to make a judgment:

The underlying implementation principle of the foreach loop is the Iterator, see Java Syntactic Sugar 1: Variable Length Parameters and the Principle of Foreach Loop. So the second half sentence "In turn, if it is accessed sequentially, it will be more efficient to use Iterator" means that the class instances that are accessed sequentially are traversed using a foreach loop.

20. Use synchronous code blocks instead of synchronous methods

This point has been explained very clearly in the article Synchronized lock method block in multi-threaded module. Unless you can determine that an entire method needs to be synchronized, try to use synchronized code blocks to avoid code that does not need to be synchronized. Synchronization was also carried out, which affected the efficiency of code execution.

21. Declare the constant as static final and name it in uppercase

In this way, these contents can be put into the constant pool during compilation, avoiding the calculation and generation of constant values ​​during runtime. In addition, naming constants in uppercase can also be used to distinguish constants from variables.

22. Don't create some unused objects, don't import some unused classes

This is meaningless. If "The value of the local variable i is not used" and "The import java.util is never used" appear in the code, then please delete these useless content

23. Avoid using reflection during program operation

About, see reflection. Reflection is a very powerful function that Java provides to users. Powerful functions often mean low efficiency. It is not recommended to use the reflection mechanism, especially the frequent use of the reflection mechanism during the running of the program, especially the invoke method of the Method. If it is really necessary, a suggested approach is to use the reflection instance of the classes that need to be loaded through reflection when the project starts. Convert an object and put it into memory—the user only cares about getting the fastest response speed when interacting with the peer, and doesn't care how long it takes for the peer's project to start.

24, use database connection pool and thread pool

These two pools are used to reuse objects, the former can avoid frequent opening and closing of connections, the latter can avoid frequent creation and destruction of threads

25. Use buffered input and output streams for IO operations

Buffered input and output streams, namely BufferedReader, BufferedWriter, BufferedInputStream, BufferedOutputStream, which can greatly improve IO efficiency

26. ArrayList is used in scenarios with more sequential insertion and random access, and LinkedList is used in scenarios with more element deletion and intermediate insertion. You will know the principles of ArrayList and LinkedList by understanding the principles of ArrayList and LinkedList.

27. Don't let the public method have too many formal parameters

Public methods are methods that are provided to the outside world. If these methods are given too many formal parameters, there are two main disadvantages:

1. It violates the idea of ​​object-oriented programming. Java emphasizes that everything is an object. Too many formal parameters do not fit the idea of ​​object-oriented programming.

2. Too many parameters will inevitably lead to an increase in the error probability of method calls

As for how many "too many" refer to, three or four. For example, we use JDBC to write an insertStudentInfo method. There are 10 student information fields to be inserted into the Student table. These 10 parameters can be encapsulated in an entity class as the formal parameters of the insert method.

28. When string variables and string constants are equals, write string constants in front

This is a relatively common trick, if you have the following code:

It is recommended to amend to:

This is mainly to avoid the null pointer exception

29. Please know that there is no difference between if (i == 1) and if (1 == i) in java, but in terms of reading habits, it is recommended to use the former

People usually ask if there is a difference between "if (i == 1)" and "if (1== i)", which should start with C/C++.

In C/C++, the "if (i == 1)" judgment condition is established. It is based on 0 and non-zero. 0 means false and non-zero means true. If there is such a piece of code:

C/C++ judges that "i==1" is not true, so it is represented by 0, which is false. but if:

In case the programmer is not careful, write "if (i == 1)" as "if (i = 1)", then there will be a problem. Assign i to 1 in the if, if the content in the judgment is not 0, the return is true, but it is clear that i is 2, the value of the comparison is 1, and it should return false. This situation is very likely to occur in the development of C/C++ and will cause some incomprehensible errors. Therefore, in order to avoid developers from incorrect assignment operations in the if statement, it is recommended to write the if statement as:

In this way, even if the developer accidentally writes "1 = i", the C/C++ compiler can check it out the first time, because we can assign i to a variable, but we cannot assign 1 to i to a constant.

However, in Java, the "if (i = 1)" syntax of C/C++ is impossible, because once this syntax is written, Java will compile and report an error "Type mismatch: cannot convert from int to boolean" ". However, although Java's "if (i == 1)" and "if (1 == i)" are not semantically different, it is better to use the former in terms of reading habits.

30. Don't use toString method on arrays

Take a look at what is printed out using toString on the array:

turn out:

The intention is to print out the contents of the array, but it may cause a null pointer exception because the array reference is is null. However, although it does not make sense for the array toString, it is possible to print the contents of the collection to the collection toString, because the parent class AbstractCollections of the collection overrides the toString method of Object.

31. Don't cast down the basic data types that are out of range

This will never get the desired result:

We may expect to get some of them, but the result is:


explain. Long in Java is 8 bytes and 64 bits, so the representation of 12345678901234 in the computer should be:

0000 0000 0000 0000 0000 1011 0011 1010 0111 0011 1100 1110 0010 1111 1111 0010

An int type data is 4 bytes 32 bits, and the first 32 bits of the above string of binary data taken from the low bits are:

0111 0011 1100 1110 0010 1111 1111 0010

This string of binary representation is decimal 1942892530, so it is what we output on the console above. Two conclusions can be drawn from this example by the way:

1. The default data type of integer is int, long l = 12345678901234L, this number has exceeded the range of int, so there is an L at the end, indicating that this is a long type number. By the way, the default type of floating-point type is double, so when defining float, it should be written as ""float f = 3.5f"

2. Next, write another sentence "int ii = l + i;" will report an error, because long + int is a long and cannot be assigned to int

32. Data that is not used in the public collection class must be removed in time

If a collection class is public (that is, it is not an attribute in a method), then the elements in the collection will not be automatically released, because there are always references to them. Therefore, if some data in the public collection is not used without removing them, it will cause the public collection to increase continuously, making the system a hidden danger of memory leakage.

33. Convert a basic data type to a string. The basic data type .toString is the fastest way, String.valueOf is the second, and data + "" is the slowest

There are three ways to convert a basic data type to general. I have an Integer type data i. You can use i.toString, String.valueOf(i), i+”” three ways, how efficient the three methods are, see a test :

The results of the operation are:

Therefore, when converting a basic data type to String in the future, the toString method is preferred. As for why, it's simple:

1. The String.valueOf method calls the Integer.toString method at the bottom, but it will make a null judgment before calling

2. I won’t talk about the Integer.toString method, just call it directly

3. The bottom layer of i + "" is implemented by StringBuilder, first use the append method to splice, and then use the toString method to get the string

Comparing the three, it is obvious that 2 is the fastest, 1 is the second, and 3 is the slowest.

34. Use the most efficient way to traverse the Map

There are many ways to traverse the Map. Generally, what we need is to traverse the Key and Value in the Map. Then the recommended and most efficient way is:

If you just want to traverse the key value of this Map, it is more appropriate to use "Set keySet = hm.keySet;"

35. Separate operations are recommended for resource close

Meaning, for example, I have such a piece of code:

It is recommended to amend to:

Although a little troublesome, it can avoid resource leakage. I think if there is no modified code, in case XXX.close throws an exception, then it enters the cath block, YYY.close will not be executed, and the resource YYY will not be recycled, and it will be occupied all the time. A lot of code may cause resource handle leaks. After changing to the above wording, it is guaranteed that XXX and YYY will be closed anyway.

At last

Welcome everyone to communicate together. If you like the article, remember to follow me and give me a like, thank you for your support!

Reference: Inventory of 35 Java code optimization details-Cloud + Community-Tencent Cloud