Java code optimization (long-term updates) and java code optimization updates
Preface
Code optimization is a very important topic. Some people may think it is useless. In some small places, what are the effects of modifying or not modifying the code on the code running efficiency? I think so. Is it useful to eat a small shrimp like a whale in the sea? It's useless, but after eating more than one shrimp, the whale will be fed. The same is true for code optimization. If the project focuses on launching without bugs as soon as possible, it can be scaled out and the code details can be refined. However, if you have enough time to develop and maintain the code, at this time, every detail that can be optimized must be considered. A small number of optimization points are accumulated, which definitely improves the code running efficiency.
The goal of code optimization is:
1. reduce the size of the Code
2. Improve code running efficiency
Some of the content in this article comes from the Internet and some from work and study at ordinary times. Of course, this is not important. What is important is whether the details of code optimization are truly useful. This article will be updated for a long time. If you encounter code optimization details worth sharing, this article will be updated from time to time.
Code optimization details
1. Specify the final modifier of classes and methods whenever possible.
Classes with final modifiers cannot be derived. In Java core APIs, 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 the method prevents the method from being overwritten. If a class is specified as final, all methods of the class are final. The Java compiler will look for opportunities to inline all final methods. inline plays a major role in improving Java runtime efficiency. For details, see Java runtime optimization. This can increase the performance by an average of 50%.
2. Try to reuse objects
In particular, the use of String objects should be replaced by StringBuilder/StringBuffer when a String connection occurs. The Java virtual machine not only takes time to generate objects, but may also take time to recycle and process these objects. Therefore, generating too many objects will greatly affect the program performance.
3. Use local variables whenever possible
Parameters passed during method call and temporary variables created in the call are saved in the stack at a high speed. other variables, such as static variables and instance variables, are created in the heap, slow speed. In addition, the variables created in the stack are no longer needed as the method stops running, and no additional garbage collection is required.
4. Close the stream in time
During Java programming, be careful when performing database connection and I/O Stream operations. after use, close the service in time to release resources. Because the operations on these large objects will cause a large overhead of the system, and a slight carelessness will lead to serious consequences.
5. Reduce repeated variable calculation as much as possible
Define a concept and call a method, even if there is only one statement in the method, it is consumption, this includes creating stack frames, protecting the site when calling methods, and restoring the site when calling methods are completed. For example:
for (int i = 0; i < list.size(); i++){...}
We recommend that you replace it:
for (int i = 0, int length = list.size(); i < length; i++){...}
In this way, when list. size () is large, a lot of consumption is reduced.
6. Try to adopt the lazy loading policy, that is, create it only when necessary.
For example:
String str = "aaa";if (i == 1){ list.add(str);}
We recommend that you replace it:
if (i == 1){ String str = "aaa"; list.add(str);}
7. Use exceptions with caution
Exceptions are detrimental to performance. To throw an exception, you must 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 processes.
8. Do not use try... catch... in a loop. Put it in the outermost layer.
Unless you have. If you write this code for no reason, as long as your senior leader has a little bit of obsessive-compulsive disorder, will scold you for writing such spam code.
9. If you can estimate the length of the content to be added, specify the initial length for the collection and tool class implemented in array mode at the underlying layer.
For example, ArrayList, LinkedLlist, StringBuilder, StringBuffer, HashMap, and HashSet. Take StringBuilder as an example:
(1) StringBuilder () // allocate 16 characters by default
(2) StringBuilder (int size) // space allocated with size characters by default
(3) StringBuilder (String str) // by default, 16 characters + str. length () are allocated.
You can set the initialization capacity of a class (not just the StringBuilder above), which can significantly improve the performance. For example, StringBuilder. length indicates the number of characters that can be maintained by the current StringBuilder. Because when StringBuilder reaches the maximum capacity, it will increase its capacity to 2 times of the current capacity and 2 times, whenever StringBuilder reaches its maximum capacity, it has to create a new character array and copy the content of the old character array to the new character array-this is a very performance-consuming operation. Imagine if we can estimate that the character array contains 5000 characters rather than the specified length, and the power of 2 power closest to 5000 is 4096. If we add 2 to each expansion, then:
(1) On the basis of 4096, apply for an array of 8194 characters, which is equivalent to applying an array of 12290 characters at a time. If you can specify an array of 5000 characters at the beginning, it saves more than doubled the space.
(2) copy the 4096 characters to the new character array.
In this way, the memory space is wasted and the code running efficiency is reduced. Therefore, it is impossible to set a reasonable initial capacity for the collection and tool classes implemented by arrays at the underlying layer, which will bring immediate results. However, note that,Like HashMap, which is a set implemented by arrays and linked lists, do not set the initial size as your estimated size, because the possibility of connecting only one object on a table is almost 0.. We recommend that you set the initial size to the N power of 2. If you can estimate that there are 2000 elements, set them to new HashMap (128) and new HashMap (256.
10. When copying a large amount of data, use the System. arraycopy () command
11. Shift operations for multiplication and division
For example:
for (val = 0; val < 100000; val += 5){ a = val * 8; b = val / 2;}
The shift operation can greatly improve the performance, because at the bottom of the computer, the operation of the position is the most convenient and fastest, so it is recommended to modify it:
for (val = 0; val < 100000; val += 5){ a = val << 3; b = val >> 1;}
Although the shift operation is fast, it may make the Code not easy to understand, so it is best to add the corresponding annotations.
12. Do not create object references continuously in a loop
For example:
for (int i = 1; i <= count; i++){ Object obj = new Object(); }
This method will cause the reference of the count Object in the memory to exist. If the count is large, the memory will be consumed. We recommend that you change it:
Object obj = null;for (int i = 0; i <= count; i++){ obj = new Object();}
In this case, there is only one Object reference in the memory. Each time a new Object () is used, the Object reference points to a different Object, but there is only one in the memory, this greatly saves the memory space.
13. Based on efficiency and type check, array should be used as much as possible. ArrayList is used only when the array size cannot be determined.
14. Use HashMap, ArrayList, and StringBuilder whenever possible. Unless thread security is required, Hashtable, Vector, and StringBuffer are not recommended. The latter three causes performance overhead due to synchronization mechanism.
15. Do not declare the array as public static final.
This is meaningless. This defines the reference as static final, and the array content can be changed at will. Declaring the array as public is a security vulnerability, this means that the array can be changed by the external class.
16. Use the singleton whenever possible
The use of Singleton can reduce the load burden, shorten the loading time, and improve the loading efficiency, but not all of them are applicable to singleton. Simply put, the Singleton is applicable to the following three scenarios:
(1) control resource usage and control concurrent resource access through thread synchronization
(2) control the generation of instances to save resources
(3) control data sharing and allow communication between multiple irrelevant processes or threads without establishing a direct Association
17. Avoid using static variables whenever possible
You must know that when an object is referenced by a variable defined as static, gc usually does not recycle the heap memory occupied by this object, for example:
public class A{ private static B b = new B(); }
In this case, the lifecycle of static variable B is the same as that of Class A. If Class A is not uninstalled, the B object referenced by Class B will stay in the memory until the program ends.
18. Clear unnecessary sessions in time
To clear sessions that are no longer active, many application servers have the default session timeout time, usually 30 minutes. When the application server needs to save more sessions, if the memory is insufficient, the operating system will transfer part of the data to the disk, and the application server may also be based on MRU (most frequently used recently) the algorithm dumps some inactive sessions to the disk, and may even throw an exception of insufficient memory. If a session is to be dumped to a disk, it must be serialized first. In a large cluster, It is very expensive to serialize the object. Therefore, when the session is no longer needed, you should promptly call the invalidate () method of HttpSession to clear the session.
19. The set that implements the RandomAccess interface, such as ArrayList, should be traversed using the most common for loop instead of foreach loop.
This is what JDK recommends to users. Jdk api's explanation for 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, therefore, it can provide good performance when applied to random or continuous access lists. Practical experience shows that,The class instance implementing the RandomAccess interface is more efficient than using the foreach loop for random access. In turn, using Iterator for sequential access is more efficient.. The following code can be used for judgment:
if (list instanceof RandomAccess){ for (int i = 0; i < list.size(); i++){}}else{ Iterator<?> iterator = list.iterable(); while (iterator.hasNext()){iterator.next()}}
The underlying implementation principle of foreach loop is Iterator. For details, see Java syntax sugar 1: Variable Length Parameter and foreach loop principle. Therefore, the second half of the sentence "in turn, if it is sequential access, it will be more efficient to use Iterator" means those class instances accessed in sequence and traverse through the foreach loop.
20. Use the synchronous code block instead of the synchronous method
This has been clearly stated in the synchronized lock method block in the multi-thread module. Unless it can be determined that the entire method needs to be synchronized, use the synchronous code block as much as possible, this prevents code that does not need to be synchronized and affects code execution efficiency.
21. Declare the constant as static final and name it in uppercase.
In this way, the content can be put into the constant pool during compilation to avoid calculating and generating the constant value during running. In addition, you can easily distinguish constants from variables by naming them in uppercase.
22. Do not create unused objects or import 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, delete these useless contents.
23. Avoid reflection when running the program
For more information, see reflection. Reflection is a powerful function provided by Java. Its powerful functions often mean low efficiency. We do not recommend that you use the reflection mechanism, especially the Method invoke Method, when the program is running. If necessary, one way to build a pipeline is to convert the classes that need to be loaded through reflection into an object during project startup and put it into the memory. Users only need to get the fastest way to interact with the peer end. response speed, it does not matter how long it takes to start a peer project.
24. Use the database connection pool and thread pool
Both pools are used to reuse objects. The former can avoid frequent opening and closing connections, and the latter can avoid frequent thread creation and destruction.
25. Use an input/output stream with buffer for IO operations
The input and output streams with buffer, namely BufferedReader, BufferedWriter, BufferedInputStream, and BufferedOutputStream, which can greatly improve IO efficiency.
26. ArrayList is used in scenarios with many sequential inserts and random accesses, and partial list is used when many elements are deleted and inserted in the middle.
In this case, you can understand the principles of ArrayList and rule list.
27. Do not make the public method have too many parameters.
The public method is an external method. If too many parameters are provided for these methods, there are two main disadvantages:
1. In violation of the object-oriented programming ideology, Java emphasizes that everything is an object and too many parameters, which is not in line with the object-oriented programming ideology.
2. Too many parameters will inevitably increase the probability of errors in method calls.
As for how many "too many" refers to, 3 and 4. For example, if we use JDBC to write an insertStudentInfo method and there are 10 Student information fields to be inserted in the Student table, we can encapsulate these 10 parameters in an object class as the form parameters of the insert method.
28. When the string variable and the String constant equals are used, write the String constant before
This is a common tips. If you have the following code:
String str = "123";if (str.equals("123")){
...
}
Recommended:
String str = "123";if ("123".equals(str)){ ...}
To avoid NULL pointer exceptions
29. Please know that in java, if (I = 1) and if (1 = I) are no different, but in terms of reading habits, we recommend that you use the former.
Some people usually ask whether there is a difference between "if (I = 1)" and "if (1 = I)". This is from C/C ++.
In C/C ++, the "if (I = 1)" condition is true. It is based on 0 and non-0. 0 indicates false, and non-0 indicates true.If there is such a piece of code:
int i = 2;if (i == 1){ ...}else{ ...}
C/C ++ determines that "I = 1" is not true, so it is expressed as 0, that is, false. However, if:
int i = 2;if (i = 1){ ...}else{ ...}
If the programmer accidentally writes "if (I = 1)" as "if (I = 1)", the problem arises. If the value of I is 1 within the if clause, if it is used to determine that the content is not 0, true is returned, but obviously I is 2, the value of comparison is 1, and false should be returned. This situation is very likely to occur in C/C ++ development and may lead to some incomprehensible errors. Therefore, to avoid incorrect value assignment in the if statement, we recommend that you write the if statement as follows:
int i = 2;if (1 == i){ ...}else{ ...}
In this way, even if the developer accidentally writes "1 = I", the C/C ++ compiler can check it as soon as possible, because we can assign an I value to a variable as 1, however, you cannot assign a value of 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)" have no difference in semantics, in terms of reading habits, it is recommended that the former be better.
30. Do not use the toString () method for Arrays
Let's take a look at what toString () is used to print the array:
public static void main(String[] args){ int[] is = new int[]{1, 2, 3}; System.out.println(is.toString());}
The result is:
[I@18a992f
The original intention is to print the array content, but it is possible that the array reference is null, leading to a null pointer exception. However, although the array toString () is meaningless, The toString () can print the content in the set, because the parent class AbstractCollections <E> of the set overrides the toString () method of the Object.
32. do not perform downward forced transformation on basic data types out of scope
This will never get the desired result:
public static void main(String[] args){ long l = 12345678901234L; int i = (int)l; System.out.println(i);}
We may expect a few of them, but the result is:
1942892530
Let's explain it. In Java, long is 8 bytes 64-bit, so the representation of 12345678901234 on 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-bit. The first 32 bits of the binary data from the low position are:
0111 0011 1100 1110 0010 1111 1111
This string is expressed as decimal 1942892530, so it is the content output on the console above. In this example, we can also draw two conclusions:
1. The default data type of an integer is int and long l = 12345678901234L. This number is beyond the int range, so there is an L at last, indicating that this is a long number. By the way, the default float type is double, so you must write "float f = 3.5f" when defining float"
2. An error is returned when I write "int ii = l + I;", because long + int is a long and cannot be assigned to int.
33. remove unused data in public collection classes in time
If a collection class is public (that is, it is not an attribute in the method), the elements in the set will not be automatically released, because there are always references pointing to them. Therefore, if some data in a public set is not used and they are not removed, the public set will increase continuously, causing memory leakage in the system.
34. convert a basic data type to a String. The basic data type. toString () is the fastest way, followed by String. valueOf (data), and the data + "" slowest
There are three methods to convert a basic data type into a general one. I have an Integer data I that can be used. toString (), String. valueOf (I), I + "" three ways, the efficiency of the three ways, look at a test:
public static void main(String[] args){ int loopTime = 50000; Integer i = 0; long startTime = System.currentTimeMillis(); for (int j = 0; j < loopTime; j++) { String str = String.valueOf(i); } System.out.println("String.valueOf():" + (System.currentTimeMillis() - startTime) + "ms"); startTime = System.currentTimeMillis(); for (int j = 0; j < loopTime; j++) { String str = i.toString(); } System.out.println("Integer.toString():" + (System.currentTimeMillis() - startTime) + "ms"); startTime = System.currentTimeMillis(); for (int j = 0; j < loopTime; j++) { String str = i + ""; } System.out.println("i + \"\":" + (System.currentTimeMillis() - startTime) + "ms");}
The running result is:
String.valueOf():11msInteger.toString():5msi + "":25ms
Therefore, when converting a basic data type to a String type, the toString () method is preferred. As for why, it is very simple:
1. The Integer. toString () method is called at the underlying layer of the String. valueOf () method, but it is judged to be short before the call.
2. the Integer. toString () method is called directly.
3. The underlying layer of I + "is implemented using StringBuilder. It is spliced using the append method and then obtained using the toString () method.
The comparison between the three is obviously the fastest in 2, the second in 1, and the slowest in 3.
35. Traverse Map in the most efficient way
There are many ways to traverse the Map. In general scenarios, We need to traverse the Key and Value in the Map. We recommend that you use the most efficient method:
public static void main(String[] args){ HashMap<String, String> hm = new HashMap<String, String>(); hm.put("111", "222"); Set<Map.Entry<String, String>> entrySet = hm.entrySet(); Iterator<Map.Entry<String, String>> iter = entrySet.iterator(); while (iter.hasNext()) { Map.Entry<String, String> entry = iter.next(); System.out.println(entry.getKey() + "\t" + entry.getValue()); }}
If you just want to traverse the key value of this Map, it is more appropriate to use "Set <String> keySet = hm. keySet ();"
Postscript
Excellent code comes from every small optimization. Focusing on every detail not only improves program running efficiency, but also avoids many unknown problems.