Joke Collection Website - Public benefit messages - How to optimize JAVA code and improve execution efficiency
How to optimize JAVA code and improve execution efficiency
The resources available to the program (memory, CPU time, network bandwidth, etc.) are limited. The purpose of optimization is to allow the program to complete the scheduled tasks with as few resources as possible. Optimization usually includes two aspects: reducing the size of the code and improving the operating efficiency of the code. This article mainly discusses how to improve the efficiency of code.
In Java programs, most of the causes of performance problems do not lie in the Java language, but in the program itself. It is very important to develop good coding habits, such as using the java.lang.String class and the java.util.Vector class correctly and skillfully, which can significantly improve the performance of the program. Let's analyze this issue in detail below.
1. Try to specify the final modifier of the class. Classes with final modifiers cannot be derived. 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 a class is designated as final, all methods of the class will be final. The Java compiler will look for opportunities to inline all final methods (this depends on the specific compiler implementation). This can improve performance by an average of 50%
.
2. Reuse objects as much as possible. Especially when using String objects, StringBuffer should be used instead when string concatenation occurs. Because the system not only takes time to generate objects, it may also take time to garbage collect and process these objects later. 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 during the call are all saved in the stack (Stack), which is faster. Other variables, such as static variables, instance variables, etc., are created in the Heap and are slower. In addition, depending on the specific compiler/JVM, local variables may be further optimized. See Use Stack Variables Wherever Possible.
4. Do not initialize variables repeatedly. By default, when calling the constructor of a class,
Java will initialize variables to a certain value: all objects are set to null, integers 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 especially noted when a class is derived from another class, because when an object is created using the new keyword, all constructors in the constructor chain will be automatically called.
5. In the development of JAVA + ORACLE application systems, the SQL statements embedded in Java should be in uppercase as much as possible to reduce the parsing burden of the ORACLE parser.
6. During Java programming, be careful when performing database connections and I/O stream operations. After use, even close to release resources. Because operating these large objects will cause a lot of system overhead, a little carelessness will lead to serious consequences.
7. Since the JVM has its own GC mechanism, it does not require too much consideration by program developers, which reduces the burden on developers to a certain extent, but at the same time it also misses hidden dangers and excessive object creation. It will consume a large amount of system memory, and in severe cases may lead to memory leaks. Therefore, it is of great significance to ensure the timely recycling of expired objects. The condition for JVM to collect garbage is that the object is no longer referenced; however, the JVM's GC is not very smart, and even if the object meets the conditions for garbage collection, it may not be recycled immediately. Therefore, it is recommended that we manually set it to null after using the object.
8. When using synchronization mechanism, try to use method synchronization instead of code block synchronization.
9. Minimize repeated calculations of variables
For example: for(int i = 0;i < list.size; i ++) {
…
}
Should be replaced with:
for(int i = 0,int len ??= list.size();i < len; i ++ ) {
…
}
10. Try to adopt the lazy loading strategy, that is, start creating when needed.
For example: String str = "aaa";
if(i == 1) {
list.add(str);
< p>}Should be replaced with:
if(i == 1) {
String str = "aaa";
list.add(str);
}
11. Use exceptions with caution
Exceptions are detrimental to performance. Throwing an exception first creates a new object. The constructor of the Throwable interface calls the Native method named fillInStackTrace(). The fillInStackTrace() method checks the stack and collects call tracing information. Whenever an exception is thrown, the VM has to adjust the call stack because a new object is created during processing. Exceptions should only be used for error handling and should not be used to control program flow.
12. Do not use it in a loop:
Try {
} catch() {
}
It should be placed on the outermost layer.
13. Use of StringBuffer:
StringBuffer represents a variable, writable string.
There are three construction methods:
StringBuffer (); //Allocate 16 characters of space by default
StringBuffer (int size); //Allocate size Character space
StringBuffer (String str); //Allocate 16 characters + str.length() character space
You can set it through the StringBuffer constructor Initialize capacity, which can significantly improve performance. The constructor mentioned here is StringBuffer(int
length), and 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 a 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 maintains a character array internally. When you use the default constructor to create a StringBuffer object, because the initial character length is not set, the capacity of StringBuffer is initialized to 16 characters, that is to say The default capacity is 16 characters. When StringBuffer reaches its maximum capacity, it will increase its capacity to 2 times the current value plus 2, that is (2*old value + 2).
If you use the default value, and then append characters to it after initialization, when you append to the 16th character, it will increase the capacity to 34 (2*16+2), and when you append to 34 characters, it will Increase capacity to 70 (2*34+2). Whenever the StringBuffer reaches its maximum capacity, it has to create a new character array and copy both the old and new characters again - which is too expensive. Therefore, it is correct to always set a reasonable initial capacity value for StringBuffer, which will bring immediate performance gains.
The effect of adjusting the StringBuffer initialization process can be seen from this. Therefore, it is always the best suggestion to initialize StringBuffer with an appropriate capacity value.
14. Use the Java class java.util.Vector properly.
Simply put, a Vector is an array of java.lang.Object instances. A Vector is similar to an Array in that its elements can be accessed via integer indexes. However, after a Vector type object is created, the size of the object can be expanded or reduced according to the addition or deletion of elements. Please consider the following example of adding elements to a Vector:
Object obj = new Object();
Vector v = new Vector(100000);
for (int I=0;
I<100000; I++) { v.add(0,obj); }
Unless there are absolutely sufficient reasons to add new elements every time Insert into the front of the Vector, otherwise the above code will be detrimental to performance. 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 just like the 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 orders of magnitude faster than the previous example:
Object obj = new Object();
Vector v = new Vector(100000);
< p>for(int I=0; I<100000; I++) { v.add(obj); }The same rule also applies to the remove() method of the Vector class. Since there cannot be "gaps" between elements in Vector, deleting any other element except the last element will cause the elements after the deleted element to move forward. In other words, deleting the last element from a Vector is several times less expensive than deleting the first element.
Suppose 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, compared to the following code, the previous code is several orders of magnitude slower:< /p>
for(int I=0; I<100000; I++)
{
v.remove(v.size()-1);
}
The best way to remove all elements from an object v of type Vector is:
v.removeAllElements();
Assuming type Vector The object v contains the string "Hello".
Consider the following code, which removes the "Hello" string from this Vector:
String s = "Hello";
int i = v.indexOf(s);< /p>
if(I != -1) v.remove(s);
This code does not look wrong, but it is also detrimental to performance. In this code, the indexOf() method performs a sequential search on v to find the string "Hello", and the remove(s) method also performs the same sequential search. 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 precise index position of the element to be deleted in the remove() method, thus avoiding a second search. A better version is:
String s = "Hello"; v.remove(s);
Finally, let's look at a code snippet about the Vector class:
p>for(int I=0; I++;I < v.length)
If v contains 100,000 elements, this code snippet will call the v.size() method 100,000 times. Although the size method is a simple method, it still requires 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 is best 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 precious. 15. When copying a large amount of data, use the System.arraycopy() command. 16. Code refactoring: Enhance the readability of the code. For example: public class ShopCart { private List carts ; … public void add ( Object item) { if(carts == null) { carts = new ArrayList(); } crts. add(item); } public void remove(Object item) { if(carts. contains(item)) {
}
}
public List getCarts() {
//Return read-only List
return Collections.unmodifiableList(carts);
}
//This method is not recommended
//this.getCarts ().add(item);
}
17. Create an instance of a class without using the new keyword
When using the new keyword to create an instance of a class, All constructors in the constructor chain are automatically called. But if an object implements the Cloneable interface, we can call its clone() method.
The clone() method does not call any class constructors.
When using Design Pattern, if you use Factory mode to create an object, it is very simple to use the 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() { p>
return (Credit) BaseCredit.clone();
}
The above idea is also very 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 operations with shift operations can greatly improve performance. The following is the modified code:
for (val = 0; val < 100000; val += 5) {
alterX = val << 3; myResult = val << 1 ;
}
The modified code no longer performs the operation of multiplying by 8, but instead uses the equivalent operation of shifting 3 bits to the left. Each left shift of 1 bit is equivalent to multiplying Take 2. Correspondingly, a right shift operation of 1 bit is equivalent to dividing by 2. It is worth mentioning that although the shift operation is fast, it may make the code more difficult to understand, so it is best to add some comments.
19. Close useless sessions in JSP pages.
A common misunderstanding is that the session is created when a client accesses it. However, the fact is that it is not created until a server-side program calls a statement such as HttpServletRequest.getSession(true). Note that if JSP If you use <%@pagesession="false"%> to close the session without display, the JSP file will automatically add such a statement HttpSession
when it is compiled into a Servlet. session = HttpServletRequest.getSession(true); This is also the origin of the implicit session object in JSP. Since session consumes memory resources, if you do not plan 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 the application needs to access a large data set, You should consider using block extraction. By default, JDBC fetches 32 rows of data at a time. For example, assuming we want to traverse a 5,000-row recordset, JDBC must call the database 157 times to extract all the data. If you change the block size to 512, the number of database calls will be reduced to 10.
[p][/p]21. Servlets and Memory Usage
Many developers arbitrarily save large amounts of information into user sessions. Sometimes, objects stored in the session are not recycled by the garbage collection mechanism in time.
From a performance perspective, a typical symptom is that users feel that the system is periodically slowing down, but cannot attribute the cause to any specific component. If you monitor the heap space of the JVM, its performance is that the memory usage rises and falls abnormally.
There are two main ways to solve this type of memory problem. The first approach is to implement the HttpSessionBindingListener interface in all session-scoped beans. 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 invalidate the session as soon as possible. Most application servers have the option to set the session expiration interval. In addition, you can also call the session's setMaxInactiveInterval() method programmatically. This method is used to set the maximum interval in seconds between client requests allowed by the Servlet container before invalidating the session.
22. Use buffer tags
Some application servers have added buffer tag functions for JSP. For example, BEA's WebLogic Server supports this feature starting from version 6.0, and the Open
Symphony project also supports this feature. The JSP buffer tag can buffer both page fragments and the entire 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. Page-level buffering captures requests for a specified URL and buffers the entire resulting page. This feature is extremely useful for shopping carts, catalogs, and portal homepages. For such applications, page-level caching can save the results of page execution for subsequent requests.
23. Choose an appropriate reference mechanism
In a typical JSP application system, the header and footer parts are often extracted, and then introduced as needed. Currently, there are two main ways to introduce external resources into JSP pages: include instructions and include actions.
include directive: for example <%@ include file="copyright.html"
%>. This directive introduces the specified resource at compile time. Before compilation, pages with include directives and specified resources are combined into a single file. The referenced external resources are determined at compile time, which is more efficient than determining the resources at runtime.
include action: for example />. This action introduces the results generated after the execution of the specified page. Since it's done at runtime, you have more flexible control over the output. However, it is only worthwhile to use the include action when the referenced content changes frequently, or when the referenced page cannot be determined before a request for the main page occurs. 24. Clear sessions that are no longer needed in a timely manner In order to clear sessions that are no longer active, many application servers have a default session timeout, generally 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 the disk, and the application server may also use the "Most Recently Used" (Most Recently Used) algorithm dumps part of the inactive session to disk, and may even throw an "out of memory" exception. In large-scale systems, serializing sessions is expensive. When the session is no longer needed, the HttpSession.invalidate() method should be called promptly to clear the session. The HttpSession.invalidate() method can usually be called on the exit page of the application. 25. Do not declare the array as: public static final. 26. Discussion on the traversal efficiency of HashMap We often encounter traversal operations on key and value pairs in HashMap. There are two methods: Map ............//First loop Set for (String appFieldDefId : appFieldDefIds) { String[] values ??= paraMap.get(appFieldDefId); ...... } //Second loop for(Entry String appFieldDefId = entry.getKey(); String[] values ??= entry.getValue(); .. ..... } The first implementation is obviously not as efficient as the second implementation. The analysis is as follows Set The code is as follows: public Set Set return (ks != null ? ks : (keySet = new KeySet()));
private class KeySet extends AbstractSet
public Iterator
return newKeyIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsKey(o);
}
public boolean remove(Object o) {
return HashMap.this.removeEntryForKey (o) != null;
}
public void clear() {
HashMap.this.clear();
}
}
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 again
for(declaration: expression_r)
statement
is translated into The following formulas
for(Iterator
declaration = #i.next( );
statement
}
So in the first for statement for (String appFieldDefId : appFieldDefIds) HashMap.keySet().iterator( ) and this method calls newKeyIterator()
Iterator
return new KeyIterator();
}
< p>private class KeyIterator extends HashIteratorpublic K next() {
return nextEntry().getKey();
} p>
}
So it is still called in for
In the second loop for(Entry
private class EntryIterator extends HashIterator
public Map.Entry
return nextEntry();
}
}
At this time, the first loop gets the key, and the second Loop to get the Entry of HashMap
The efficiency is reflected in the loop. Sincerely, the second loop can directly get the key and value values
But the first loop still has to reuse the HashMap. get(Object key) to get the value
Now look at the get(Object key) method of HashMap
public V get(Object key) {
Object k = maskNull(key);
int hash = hash(k);
int i = indexFor(hash, table.length); //Entry[] table
Entry
while (true) {
if (e == null)
return null;
if (e.hash == hash && eq(k, e.key))
return e.value;
e = e.next;
}
}
In fact, it is to use the Hash value again to take out the corresponding Entry for comparison to get the result, so using the first loop is equivalent to entering the HashMap twice. Entry
The second loop obtains the value of Entry and directly obtains the key and value, 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 pair of key and value. It is not a good choice to operate key and value separately here.
- Previous article:Customer service work plan
- Next article:A short copy of the wedding anniversary
- Related articles
- How does Pinduoduo give favorable comments to businesses?
- How to print the monthly invoice in the business hall when the mobile payment invoice is lost?
- What are the COVID-19 vaccination sites in Xiamen?
- Please, recommend me a mobile phone package. What's your first thought?
- Did the leader write a special guest at the meeting?
- What if I can't receive the verification code after registration?
- What do you mean by sending a short message receipt?
- Five tips for girls to change their avatars
- 2020 Hebei Normal University Higher Education Continuing Education Admissions Guide?
- Phone number report: harassing phone calls. Caller ID number: 025689079 12 Caller company name: A complete liar company, pretending to be an acquaintance or family member to cheat.