29 key points to help you complete Java code optimization
Optimize the program through Java code specification, optimize memory usage and prevent memory leakage
Resources available to programs (memory, CPU time, network bandwidth, etc.) is limited. The purpose of optimization is to make the program complete the predetermined task with as few resources as possible. Optimization usually includes two aspects: reducing the size of the code and improving the running efficiency of the code. This paper mainly discusses how to improve the efficiency of the code. In Java programs, most of the performance problems do not lie in Java Language, but the program itself. It is very important to develop good coding habits, such as using java correctly and skillfully Lang.string class and Java util. Vector class, which can significantly improve the performance of the program. Let's specifically analyze the problems in this regard.
1. Try to specify the final modifier of the class. Classes with the final modifier are not derivable. In the Java core API, there are many examples of applying final, such as Java lang.String。 Specifying final for the string class prevents people from overriding the length () method. In addition, if you specify a class as final, all methods of that class are final. The java compiler looks for an opportunity to inline all final methods (depending on the compiler implementation). This can improve performance by an average of 50%.
2. Reuse objects as much as possible. Especially in the use of string objects, when string connection occurs, StringBuffer should be used instead. Since the system 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. Try to use local variables, The parameters passed when calling the method and the temporary variables created in the call are saved in the stack, which is faster. Other variables, such as static variables and instance variables, are created in the heap, which is slower. In addition, depending on the specific compiler / JVM, local variables may be further optimized. See using stack variables as much as possible.
4. Do not initialize variables repeatedly. By default, when calling the constructor of a class, Java initializes the variables to a certain value: all objects are set to null, Integer variables (byte, short, int, long) are set to 0, float and double variables are set to 0.0, and logical values are set to false. This should be particularly noted when a class derives from another class, because when an object is created with the new keyword, all constructors in the constructor chain will be called automatically.
5. In the development of java + Oracle application system, the SQL statements embedded in Java should be capitalized as much as possible to reduce the parsing burden of Oracle parser.
6. In the process of Java programming, be careful when performing database connection and I / O flow operations. After use, even close it to release resources. Because the operation of these large objects will cause large system overhead. If you are careless, it will lead to serious consequences.
7. Because the JVM has its own GC mechanism, it does not need the excessive consideration of program developers, which reduces the burden of developers to a certain extent, but also omits hidden dangers. Excessive creation of objects will consume a lot of memory of the system, and in serious cases, it will lead to memory leakage. Therefore, it is of great significance to ensure the timely recovery of expired objects. The conditions for JVM garbage collection are: the object is no longer referenced; However, the GC of the JVM is not very clever. Even if the object meets the garbage collection conditions, it may not be recycled immediately. Therefore, it is recommended that we manually set the object to null after it is used.
8. When using the synchronization mechanism, we should try to use method synchronization instead of code block synchronization.
9. Minimize repeated calculation of variables. For example, for (int i = 0; I < list. Size; I + +) {...} should be replaced by: for (int i = 0, int len = list. Size(); i < len; i ++){ … }
10. Try to adopt the strategy of lazy loading, that is, start creating when necessary.
For example: String STR = "AAA"; if(i == 1) { list.add(str); } Should be replaced by: if (I = = 1) {string STR = "AAA"; list. Add (STR);}
11. Use with caution
Exceptions are detrimental to performance. To throw an exception, first create a new object. The constructor of throwable interface calls the native method named fillinstacktrace(). The fillinstacktrace() method checks the stack and collects call trace information. Whenever an exception is thrown, the VM 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.
12. Do not use in a loop:
Try {} catch() {} should place it on the outermost layer.
13. Use of StringBuffer:
StringBuffer represents a variable, writable string. There are three construction methods: stringbuffer()// By default, 16 character space StringBuffer (int size) is allocated// Allocate a space of size characters StringBuffer (string STR)// Allocate 16 characters + str.length () character space. You can set its initialization capacity through the constructor of StringBuffer, which can significantly improve performance.
The constructor mentioned here is StringBuffer (int length). The length parameter indicates the number of characters that the current StringBuffer can hold. You can also use the ensurecapacity (int minimumcapacity) method to set the capacity of the StringBuffer object after it is created. First, let's look at the default behavior of StringBuffer, and then find a better way to improve performance. StringBuffer internally maintains a character array. When you use the default constructor to create a StringBuffer object, because the initialization character length is not set, the capacity of StringBuffer is initialized to 16 characters, that is, the default capacity is 16 characters. When the StringBuffer reaches its maximum capacity, it will increase its capacity to twice the current capacity plus 2, That is (2 * old value + 2). If you use the default value, add characters after initialization. When you add to the 16th character, it will increase the capacity to 34 (2 * 16 + 2). When you add to 34 characters, it will increase the capacity to 70 (2 * 34 + 2). No matter what, as long as the StringBuffer reaches its maximum capacity, it has to create a new character array and then copy the old and new characters again. DD is too expensive. Therefore, it is not wrong to always set a reasonable initialization capacity value for the StringBuffer, which will bring immediate performance gain. StringBuffer initialization process From this we can see the role of the adjustment of. Therefore, using an appropriate capacity value to initialize StringBuffer is always the best suggestion.
14. Rational use of Java classes util. Vector。
Simply put, a vector is a Java An array of lang.Object instances. Vector is similar to an array in that its elements can be accessed through an index in the form of an integer. However, after an object of vector type is created, the size of the object can be expanded or reduced according to the increase or deletion of elements. Consider the following example of adding elements to a vector: object BJ = new object(); Vector v = new Vector(100000); for(int I=0; I<100000; I++) { v.add(0,obj); }
The above code is bad for performance unless there is absolutely good reason to insert a new element in front of the vector every time. In the default constructor, the initial storage capacity of vector is 10 elements. If the storage capacity is insufficient when new elements are added, the storage capacity will be doubled each time in the future. The vector class is the same as the object StringBuffer class. Every time the storage capacity is expanded, all existing elements must be copied to the new storage space. The following code snippet is several orders of magnitude faster than the previous example: object BJ = new object(); Vector v = new Vector(100000); for(int I=0; I<100000; I++) { v.add(obj); }
The same rule applies to the remove () method of the vector class. Since there can be no "gap" between each element in the vector, deleting any element other than the last element will cause the element after the deleted element to move forward. That is, deleting the last element from the vector is several times less "expensive" than deleting the first element.
Assuming that we want to delete all elements from the previous vector, we can use this Code: for (int i = 0; I < 100000; I + +) {v.remove (0);}
However, the previous code is several orders of magnitude slower than the following code: for (int i = 0; I < 100000; I + +) {v.remove (v.size() - 1);}
The best way to V delete all elements from an object of type vector is: v. removeallelements();
Suppose an object of type vector V contains the string "hello". Consider the following code to remove the "hello" string from this vector: String s = "hello"; int i = v.indexOf(s); if(I != -1) v.remove(s);
The code looks fine, but it's also bad for performance. In this code, the indexof () method searches V sequentially for the string "hello", and the remove (s) method does the same. The improved version is: String s = "hello"; int i = v.indexOf(s); if(I != -1) v.remove(i);
In this version, we directly give the exact index position of the element to be deleted in the remove () method, so as to avoid the second search. A better version is: String s = "hello"; v.remove(s);
Finally, let's look at a code fragment about the vector class: for (int i = 0; I + +; I < v.length)
If V contains 100000 elements, this code fragment will call the v. size () method 100000 times. Although the size method is a simple method, it still needs the overhead of a method call. At least the JVM needs to configure and clear the stack environment for it. Here, the code inside the for loop will not modify the size of the vector type object v in any way, so the above code should be rewritten into the following form: int size = v.size(); for(int I=0; I++;I
Although this is a simple change, it still wins performance. After all, every CPU cycle is valuable.
15. When copying large amounts of data, use system Arraycopy() command.
16. Code refactoring: enhance the readability of code. For example:
17. Create an instance of a class without the new keyword
When you create an instance of a class with the new keyword, all constructors in the constructor chain will be called automatically. But if an object implements the clonable interface, we can call its clone () method. The clone () method does not call any class constructors. When using design pattern, if you create an object in factory mode, it is very simple to use clone () method to create a new object instance. For example, the following is a typical implementation of the factory pattern: public static credit getnewcredit() {return new credit();} The improved code uses the clone () method, as follows: private static credit basecredit = new credit(); public static Credit getNewCredit() { return (Credit) BaseCredit.clone(); } The above ideas are also useful for array processing.
18. Multiplication and division
Consider the following code: for (Val = 0; Val < 100000; Val + = 5) {alterx = Val * 8; myresult = Val * 2;} Replacing multiplication with shift operation can greatly improve performance. The following is the modified code: for (Val = 0; Val < 100000; Val + = 5) {alterx = Val < < 3; myresult = Val < < 1;} Instead of multiplying by 8, the modified code uses the equivalent operation of shifting 3 bits to the left. Each shift of 1 bit to the left is equivalent to multiplying by 2. Accordingly, the shift 1 bit right operation is equivalent to dividing by 2. It is worth mentioning that although the shift operation is fast, it may make the code difficult to understand, so it is best to add some comments.
19. Close useless sessions in JSP pages.
A common misconception is that a session is created when there is client access. However, the fact is that it is not until a server-side program calls HttpServletRequest A statement such as getsession (true) is created. Note that if the JSP does not display a statement such as < > Close session, the JSP file will automatically add such a statement httpsession = HttpServletRequest when it is compiled into a servlet getSession(true); This is also the origin of the session object implied in JSP. Since session consumes memory resources, if you do not intend to use session, you should close it in all JSPS. For pages that do not need to track session status, turning off automatically created sessions can save some resources. Use the following page command: <% @ page session = "false"% >
20. JDBC and I / O
If your application needs to access a large data set, you should consider using block extraction. By default, JDBC extracts 32 rows of data at a time. For example, if we want to traverse a record set of 5000 rows, JDBC must call the database 157 times to extract all the data. If the block size is changed to 512, the number of calls to the database will be reduced to 10.
21. Servlet and memory usage many developers arbitrarily save a large amount of information into user sessions. Sometimes, the objects saved in the session are not collected by the garbage collection mechanism in time. In terms of performance, the typical symptom is that users feel that the system slows down periodically, but they can't attribute the reason to any specific component. If you monitor the heap space of the JVM, its performance is that the memory usage fluctuates abnormally. There are two main ways to solve this kind of memory problem. The first approach is to implement the HttpSessionBindingListener interface in all beans whose scope is session. In this way, as long as the valueunbound () method is implemented, the resources used by the bean can be explicitly released.
Another way is to void the session as soon as possible. Most application servers have the option to set the session invalidation interval. In addition, you can programmatically call the setmaxinactivival () method of the session, which is used to set the maximum interval of client requests allowed by the servlet container before voiding the session, in seconds.
22. Use buffer mark
Some application servers have added JSP oriented buffer tag function. For example, BEA's WebLogic Server supports this function from version 6.0, and the open Symphony project also supports this function. JSP buffer tags can buffer not only page fragments, but also the whole page. When the JSP page is executed, if the target fragment is already in the buffer, the code that generates the fragment does not need to be executed. The page level buffer captures the request for the specified URL and buffers the entire result page. This feature is extremely useful for shopping baskets, directories, and the home page of the portal. For such applications, page level buffering can save the results of page execution for subsequent requests.
23. Select the appropriate reference mechanism
In a typical JSP Application System, the header and footer are often extracted, and then the header and footer are introduced as needed. At present, there are two main methods to introduce external resources into JSP pages: include instruction and include action. Include instruction: for example, <% @ include file = "copyright. HTML"% >. This directive introduces the specified resource at compile time. Before compiling, the page with the include directive and the specified resources are merged into a file. The referenced external resources are determined at compile time, which is more efficient than determining resources at run time. Include action: for example, < jsp: include page = "copyright. JSP" / >. This action introduces the results generated after the execution of the specified page. Because it is completed at run time, the control of output results is more flexible. However, it is only cost-effective to use the include action when the referenced content changes frequently, or the referenced page cannot be determined before the request for the main page appears.
24. Clear unnecessary sessions in time
In order to clear inactive sessions, many application servers have a default session timeout of 30 minutes. When the application server needs to save more sessions, if the memory capacity is insufficient, the operating system will transfer part of the memory data to disk, The application server may dump some inactive sessions to disk according to the most recently used algorithm, and may even throw "out of memory" exceptions. In large-scale systems, the cost of serializing sessions is very expensive. When the session is no longer needed, the httpsession. Invalidate() method should be called in time to clear the session. HttpSession. The invalidate () method can usually be called on the exit page of an application.
25. Do not declare the array as public static final.
26. Discussion on traversal efficiency of HashMap
Traversal of key and value pairs in HashMap is often encountered. There are two methods: Map < string, string [] > paramap = new
The first implementation is obviously less efficient than the second implementation. The analysis is as follows: set < string > appfielddefinitions = paramap keySet(); First, get the keyset from the HashMap
The code is as follows:
In fact, it returns a private class keyset, which inherits from abstractset and implements the set interface.
Let's look at the syntax of the for / in loop: for (Declaration: expression) statement
In the execution stage, it is translated into the following expressions: for (iterator < E > #i = (expression) iterator(); # i.hashNext();) { declaration = #i.next(); statement }
Therefore, HashMap. is called in the first for statement for (String appFieldDefId: appFieldDefIds). keySet(). iterator()
This method calls newkeyiterator()
Iterator
newKeyIterator() { return new KeyIterator(); } private class KeyIterator extends HashIterator
{ public K next() { return nextEntry().getKey(); } }
Therefore, in for, the iterator used in the second loop for (entry < string, string [] > entry: paramap. Entryset()) is called. It is an internal loop as follows
class
private class EntryIterator extends HashIterator
next() { return nextEntry(); } }
At this point, the first loop gets the key, The entry efficiency of HashMap obtained in the second loop is reflected in the loop. In the second loop, you can directly get the key and value values. In the first loop, you still have to use HashMap's get (object key) to get the value value. Now look at HashMap's get (object key) method public V get (object key) {object k = masknull (key); int hash = hash (k); int i = indexfor (hash,table.length); // Entry[] table Entry
e = table; while (true) { if (e == null) return null; if (e.hash == hash && eq(k,e.key)) return e.value; e = e.next; } } In fact, the hash value is used again to take out the corresponding entry for comparison, so using the first cycle is equivalent to entering the entry of HashMap twice
The second loop takes the key and value directly after obtaining the value of the entry, which is more efficient than the first loop. In fact, according to the concept of map, it should be better to use the second loop. It is originally a value pair of key and value. It is not a good choice to operate key and value separately.
27. Use of array and ArrayList
array([] ): most efficient; However, its capacity is fixed and cannot be changed dynamically; ArrayList: capacity can grow dynamically; But at the expense of efficiency; Based on efficiency and type checking, array should be used as much as possible. ArrayList should be used only when the array size cannot be determined! ArrayList is a complex version of array. ArrayList encapsulates an array of object type. In a general sense, it has no essential difference from array. Even many methods of ArrayList, such as index, indexof, contains, sort, etc., directly call the corresponding methods of array based on the internal array. When an ArrayList is stored in an object, the type information is discarded, and all objects are masked as objects. The type is not checked during compilation, but an error will be reported at run time. Note: jdk5 has added support for generics, so you can check the type when using ArrayList. From this point of view, the difference between ArrayList and array is mainly due to the efficiency of dynamic capacity expansion
28. Try to use HashMap and ArrayList. Unless necessary, hashtable and vector are not recommended. The latter leads to performance overhead due to the use of synchronization mechanism.
29. The difference between StringBuffer and StringBuilder:
java. Lang.stringbuffer thread safe variable character sequence. A string buffer similar to string, but cannot be modified.
StringBuilder。 Compared with this class, you should usually give priority to Java Lang. StringBuilder class, because it supports all the same operations, but because it does not perform synchronization, it is faster. For better performance, you should specify the capacity of stirngbuffer or stirngbuilder as much as possible. Of course, if the length of the string you operate on is no more than 16 characters, you don't have to. In the same case, using stirngbuilder can only improve the performance by about 10% - 15% compared with using StringBuffer, but it takes the risk of unsafe multithreading. The first mock exam is not necessarily able to clearly determine whether the module will run in a multithreading environment. So unless you can make sure that the bottleneck of your system is on StringBuffer and make sure that your module will not run in multithreading mode, use StringBuffer.
Other supplements:
1. Clear objects that are no longer used in time and set them to null. 2. Use final, static and other keywords as much as possible. 3. Use buffered objects as much as possible
How to optimize the code to make the Java source file and the compiled class file smaller 1. Try to use inheritance. The more inheritance methods, the less code you need to write. 2. Open the optimization option of the java compiler: javac - O. this option will delete the line numbers in the class file and put some private, static, Final's short method is declared as an inline method call. 3. Extract the common code. 4. Do not initialize a large array. Although initializing an array is only a line of code in Java code, the compiled code is a line of code inserted into the elements of an array, so if you have a large amount of data that needs to be stored in the array, You can put these data in the string first, and then parse the string into the array at run time. 5 date type objects will take up a lot of space. If you want to store a large number of date objects, you can consider storing them as long, and then converting them to date type 6 class names. Try to use short names for method names and variable names, Consider using tools such as hashjava, job, obfuscate and jshrink to automatically complete this work. 7 define variables of static final type into the interface. 8 do not use * and / for arithmetic operations that can shift left / right, and do not operate the same operation multiple times
2. Do not initialize the variable twice. Java initializes the variable to a known value by default by calling a unique class constructor. All objects are set to null, integers (byte, short, int, long) is set to 0, float and double are set to 0.0, and Boolean variables are set to false. This is especially important for classes that extend from other classes, just as all a series of constructors are called automatically when an object is created with a new keyword. 3. Make the class final wherever possible. The class marked final cannot be extended. There are many examples of this technology in the core Java API, such as Java lang.String。 Marking the string class final prevents developers from creating their own length methods. Further, if the class is final, the methods of all classes are also final. The java compiler may inline all methods (depending on the implementation of the compiler). In my tests, I have seen an average performance increase of 50%.
9. Exceptions are thrown where they need to be thrown, and try catch can be integrated
The generated code is more easily optimized by the compiler
10. Optimized replace... For (int i = 0; I < collection. Size(); i++ ) { ... }
with… for( int i = 0,n = collection.size(); i < n; i++ ) { ... }
5. In the development of java + Oracle application system, the SQL statements embedded in Java should be capitalized as much as possible to reduce the parsing burden of Oracle parser.
10. Try to adopt the strategy of lazy loading, that is, start creating when necessary. For example: String STR = "AAA"; if(i == 1) { list.add(str); } Should be replaced by: if (I = = 1) {string STR = "AAA"; list. Add (STR);}
12. Do not use in loops: try {} catch() {} should put it on the outermost layer
The above is the whole content of this article. I hope it can be helpful to everyone's Java optimization.
Please take a moment to share the article with your friends or leave comments. We will sincerely thank you for your support!