preface
Code optimization, a very important topic. Some people may feel useless, some small places have what to modify, change or not to change the efficiency of the code what impact? I think about it this way, like the whale in the sea, it eat a small shrimp useful? It didn’t work, but after eating more shrimp, the whale was full. Code optimization is the same, if the project is aimed at bug-free online as soon as possible, then you can focus on the small, the details of the code can not be fine grinding; However, if there is enough time to develop and maintain the code, it is necessary to consider every detail that can be optimized. The accumulation of a small optimization point will definitely improve the running efficiency of the code.
The goals of code optimization are:
Reduce the size of your code
2. Improve the efficiency of code execution
Code optimization details
1. Specify final modifiers for classes and methods as much as possible
Classes with the final modifier are not derivable. In the Java core API, there are many examples of final applications, such as java.lang.String, where entire classes are final. Specifying a final modifier for a class makes it uninheritable, and specifying a final modifier for a method makes it unoverridden. If a class is specified as final, all methods of that class are final. The Java compiler looks for opportunities to inline all final methods. Inlining is important for improving Java runtime efficiency. See Java Runtime Optimization. This can improve performance by an average of 50%.
Reuse objects as much as possible
Especially the use of String object, there should use StringBuilder/StringBuffer instead of String concatenation. Because the Java virtual machine takes time not only to generate objects, but also to garbage collect and dispose of them later, generating too many objects can have a significant impact on your program’s performance.
3. Use local variables whenever possible
Parameters passed when a method is called, as well as temporary variables created during the call, are quickly stored in the stack, while other variables, such as static variables, instance variables, and so on, are created in the heap and are slower. In addition, variables created in the stack are removed as the method completes its run, requiring no additional garbage collection.
4. Close the stream in time
During Java programming, be careful when connecting to the database and performing I/O flow operations. After using the database, close the database to release resources. Because the operation of these large objects will cause a large overhead of the system, a slight mistake will lead to serious consequences.
5. Minimize the double calculation of variables
Make it clear that calls to a method, even if there is only one statement in the method, have costs, including creating stack frames, protecting the scene when the method is called, and restoring the scene when the method is finished. So for example:
for(int i = 0; i < list.size(); i++){... }Copy the code
You are advised to replace it with:
for(int i = 0, int length = list.size(); i < length; i++){... }Copy the code
This saves a lot of overhead when list.size() is large
6. Try to use a lazy loading strategy, that is, create it when you need it
Such as:
String str = "aaa";if (i == 1)
{
list.add(str);
}
Copy the code
You are advised to replace it with:
if (i == 1)
{
String str = "aaa";
list.add(str);
}
Copy the code
7. Use exceptions with caution
Exceptions are detrimental to performance. To throw an exception, a new object is created. The constructor of the Throwable interface calls a locally synchronized method called fillInStackTrace(), which checks the stack to collect the call trace information. Whenever an exception is thrown, the Java virtual machine must 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.
8. Do not use try… The catch… You should put it in the outermost layer
Unless you have to. If you do this for no reason, if your boss is a bit more senior and obsessive-compulsive, he or she will probably scold you for writing such junk code
9. If you can estimate the length of the content to be added, specify the initial length for the underlying array-based collections and utility classes
Examples include ArrayList, LinkedLlist, StringBuilder, StringBuffer, HashMap, HashSet, etc. Take StringBuilder for example:
(1) StringBuilder() // Default allocation of 16 characters space
(2) StringBuilder(int size) // Default allocation of size character space
StringBuilder(String STR) // Default allocation of 16 characters +str.length() word
Operator space
The ability to set the initialization capacity of a class (not just the StringBuilder above) can significantly improve performance. For example, StringBuilder, length is the number of characters that the current StringBuilder can hold. Because when StringBuilder reaches its maximum capacity, it increases its current capacity by two plus two, and whenever StringBuilder reaches its maximum capacity, It would have to create a new character array and copy the contents of the old character array into the new character array — a very performance expensive operation. Imagine that the array contains about 5000 characters without specifying the length, and the nearest power of 5000 is 4096, with each increment incrementing by 2:
(1) Apply for 8194 character arrays in addition to 4096, which is equivalent to applying for 12290 character arrays at one time. If you can specify 5000 character arrays at the beginning, you can save more than double the space
(2) Copy the original 4096 characters into the new character array, which not only wastes memory space but also reduces the efficiency of the code. Therefore, you can’t go wrong with setting a reasonable initialization capacity for collections and utility classes that are implemented in arrays at the bottom. This will bring immediate results. Note, however, that for collections such as a HashMap, which is implemented as an array + linked list, do not set the initial size to the size you estimated, because the probability of joining only one object on a table is almost zero. The recommended initial size is 2 to the NTH power, or new HashMap(128) or new HashMap(256) if 2000 elements are expected.
10. Run the system.arraycopy () command to copy a large amount of data
Multiplication and division use shift operations
Such as:
for (val = 0; val < 100000; val += 5)
{
a = val * 8;
b = val / 2;
}
Copy the code
Using shift operation can greatly improve performance, because at the bottom of the computer, the counterpoint operation is the most convenient and fastest, so it is recommended to change to:
for (val = 0; val < 100000; val += 5)
{
a = val << 3;
b = val >> 1;
}
Copy the code
The shift operation, while fast, can make the code difficult to understand, so it is best to comment accordingly.
12. Do not keep creating object references within the loop
Such as:
for (int i = 1; i <= count; i++)
{
Object obj = new Object();
}
Copy the code
If count is too large, the memory will be used. We recommend changing it to:
Object obj = null;for (int i = 0; i <= count; i++)
{
obj = new Object();
}
Copy the code
Each time a new Object() is called, the Object reference refers to a different Object, but there is only one Object in memory. This saves a lot of memory.
13. For efficiency and type checking purposes, use arrays whenever possible, and use ArrayList only when the size of the array is uncertain
Use HashMap, ArrayList, and StringBuilder as much as possible. Hashtable, Vector, and StringBuffer are not recommended unless thread-safe because they incur performance overhead due to synchronization
Do not declare arrays to be public static final
Declaring an array public is a security loophole, which means that the array can be changed by an external class
16, try to use singletons in appropriate situations
Singletons can reduce the load burden, shorten the load time, and improve the load efficiency. However, they are not applicable to all places. In brief, singletons are mainly applicable to the following three aspects:
(1) Control the use of resources, through thread synchronization to control the concurrent access to resources
(2) Control the generation of instances to achieve the purpose of saving resources
(3) Control the sharing of data, so as to realize communication between multiple unrelated processes or threads without establishing direct correlation
17. Avoid arbitrary use of static variables
Remember that when an object is referenced by a variable defined as static, gc usually does not reclaim the heap memory occupied by the object, as in:
/** * Java learning exchange QQ group: 956011797 We learn Java together! */ public class A { private static B b = new B(); }Copy the code
The lifetime of the static variable B is the same as that of class A. If class A is not unloaded, the object referred to by b will stay in memory until the program terminates
18. Clear up sessions that are no longer needed
To clear out inactive sessions, many application servers have a default session timeout, typically 30 minutes. When the application server needs to hold more sessions, if the memory is low, the operating system will move some of the data to disk, the application server may dump some of the inactive sessions to disk according to the MRU (most frequently used recently) algorithm, or even throw an out-of-memory exception. If a session is to be dumped to disk, it must first be serialized, and serializing objects can be expensive in a large cluster. Therefore, when a session is no longer needed, it should be immediately cleared by calling the invalidate() method of HttpSession.
19. Collections that implement the RandomAccess interface, such as ArrayList, should be traversed using the most common for loop rather than the foreach loop
This is what the JDK recommends to users. The RandomAccess interface is implemented to show that it supports fast RandomAccess. The main purpose of this interface is to allow general algorithms to change their behavior to provide good performance when applied to random or continuously accessed lists. Practical experience shows that the efficiency of using ordinary for loop is higher than foreach loop if the class instance implementing RandomAccess interface is accessed randomly. Conversely, if the access is sequential, it is more efficient to use Iterator. This can be done with code like the following:
if (list instanceof RandomAccess)
{ for (int i = 0; i < list.size(); i++){}
}else{ Iterator<? > iterator = list.iterable();while (iterator.hasNext()){iterator.next()}
}
Copy the code
The underlying implementation principle for foreach loops is the Iterator. See Java Syntax Sugar 1: Variable-length Arguments and Foreach loops. Instead, it is more efficient to use Iterator if the class is accessed sequentially.
Use synchronized code blocks instead of synchronized methods
This point has been clearly stated in the article of synchronized lock method block in multi-threaded module. Unless it can be determined that a whole method needs to be synchronized, it should try to use synchronized code block to avoid the synchronization of those codes that do not need to be synchronized, which affects the efficiency of code execution.
21. Declare constants static final and name them in uppercase
This allows you to put the content into the constant pool at compile time, avoiding the need to evaluate the value of the generated constant at run time. In addition, it is easy to distinguish constants from variables by naming them in uppercase
By the way, I would like to recommend a Java architecture exchange learning group: 956011797. Click to join it now and you will share some videos recorded by senior architects for free: Spring, MyBatis, Netty source code analysis, high concurrency, high performance, distributed, microservice architecture principles, JVM performance optimization has become an architect’s essential knowledge system. Also can receive free learning resources and predecessors of the interview experience and questions, I believe that for those who have worked and encountered technical bottlenecks, there will be content you need in this group.
Don’t create objects that you don’t use, and don’t import classes that you don’t use
This makes no sense. If “The value of The local variable I is not used”, “The import java.util is never used” appear in your code, delete these useless things
23. Avoid the use of reflection during program operation
For more information, see Reflection. Reflection is a powerful feature that Java provides to users, and powerful features often mean inefficient. It is not recommended to use invoke methods that use reflection frequently, especially Method, during program execution. If necessary, One suggested approach is to have classes that need to be loaded by reflection instantiate an object by reflection and put it into memory at project startup — the user only cares about getting the fastest response time when interacting with the peer side, not how long it takes the peer side to start the project.
24. Use database connection pools and thread pools
Both pools are designed to reuse objects, the former to avoid frequent opening and closing of connections, and the latter to avoid frequent thread creation and destruction
Use buffered INPUT/output streams for IO operations
Buffered input and output streams (BufferedReader, BufferedWriter, BufferedInputStream, BufferedOutputStream) can greatly improve I/O efficiency
26. ArrayList is used for scenarios with high sequential inserts and random access, and LinkedList is used for scenarios with high element deletions and intermediate inserts
Understand how ArrayList and LinkedList work
27. Don’t let public methods have too many parameters
Public methods are methods that are provided externally. There are two main disadvantages to giving them too many parameters:
1, violates the object-oriented programming thought, Java emphasizes that everything is an object, too many parameters, and object-oriented programming thought does not fit
2. Too many parameters will inevitably lead to an increase in the error probability of method calls
As for how many “too many” means, three or four. For example, if we write an insertStudentInfo method in JDBC and have 10 Student fields to insert into the Student table, we can wrap these 10 parameters in an entity class as parameters to the insert method
28, String variables and string constants equals before string constants
This is a common trick if you have the following code:
String str = "123";
if (str.equals("123")) {... }Copy the code
You are advised to change the value to:
String str = "123";
if ("123".equals(str))
{
...
}
Copy the code
This is mostly to avoid null-pointer exceptions
29, If (I == 1) is the same as if (1 == I) in Java
Someone asked, “if (I = = 1)” and “if (1 = = I) if there is any difference,” this is from the C/C + +.
In C/C++, the “if (I == 1)” criterion is valid, based on 0 and non-0, 0 means false, non-0 means true, if there is such a code:
int i = 2;
if (i == 1)
{
...
}else{... }Copy the code
C/C++ determines that “I ==1” is not true, so 0 is false. But if:
int i = 2;if (i = 1) { ... }else{... }Copy the code
If a programmer accidentally writes “if (I == 1)” as “if (I = 1)”, then there’s a problem. If (I = 1); if (I = 1); if (I = 1); This can happen in C/C++ development and can lead to some unintelligible errors, so to avoid incorrect assignments in if statements, it is recommended to write if statements as:
int i = 2;if (1 == i) { ... }else{... }Copy the code
This way, even if the developer accidentally writes “1 = I”, the C/C++ compiler can detect it in the first place, because we can assign I to a variable, but we cannot assign 1 to a constant.
The C/C++ syntax “if (I = 1)” is not possible in Java, however, because it would cause Java to compile an error “Type Mismatch: Cannot convert from int to Boolean”. However, while there is no semantic difference between “if (I == 1)” and “if (1 == I)” in Java, the former is recommended as a reading convention.
30. Do not use the toString() method on arrays
Take a look at what is printed using toString() on an array:
public static void main(String[] args)
{ int[] is = new int[]{1, 2, 3};
System.out.println(is.toString());
}
Copy the code
The result is:
[I@18a992f
Copy the code
The null pointer exception is possible because the array reference is null. AbstractCollections overrides the toString() method of Object, but it doesn’t make sense to print the contents of the collection toString().
31. Do not force downcasts of basic data types that are 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);
}
Copy the code
We might expect some of them, but the result is:
1942892530
Copy the code
Explain. In Java, long is 8 bytes 64-bit, so 12345678901234 should look like this:
0000 0000 0000 0000 0000 1011 0011 1010 0111 0011 1100 1110 0010 1111 1111 0010
The first 32 bits of an int are the same as the first 32 bits of an int:
0111 0011 1100 1110 0010 1111 1111 0010
This string of binary is represented as decimal 1942892530, so that’s what our console output is above. Two further conclusions can be drawn from this example:
Int l = 12345678901234L (12345678901234L, 12345678901234L, 12345678901234L); By the way, the default floating-point type is double, so you define float as “float f = 3.5f”
Int ii = l + I; An error is reported because long + int is a long and cannot be assigned to int
Public collection class not used data must be removed in time
If a collection class is public (that is, not an attribute in a method), the elements in the collection are not automatically freed because there are always references to them. Therefore, if some data in the public set is not used but not removed, it will cause the public set to increase, so that the system has the potential of memory leakage.
ToString () is the fastest way to convert a basic datatype to a String, followed by String.valueof (data) and data + “(“)
There are three general ways to convert a basic datatype. I have an Integer I, and I can use i.tostring (), string.valueof (I), and I + “.
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. The valueOf () :" + (System.currentTimeMillis() - startTime) + "ms");
startTime = System.currentTimeMillis(); for (int j = 0; j < loopTime; j++)
{
String str = i.toString();
}
System.out.println("Is an Integer. The 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");
}
Copy the code
The running results are as follows:
String.valueof () : 11ms Integer.toSTRING () : 5ms I +"": 25 msCopy the code
Therefore, the toString() method will be preferred when converting a primitive data type toString. As for why, it’s simple:
ValueOf () calls integer.tostring (), but shorts it before calling it
The integer.tostring () method is called directly
3. The bottom layer of I + “” uses StringBuilder. Append method is used first, and then toString() method is used to get the string
Compared with 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 a Map. Generally, we need to traverse keys and values in a Map. The most efficient way is recommended as follows:
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()); }}Copy the code
If you just want to iterate over the Map’s keys, use “Set keySet = hm.keyset ();” Would be more appropriate
35. It is recommended to separate close() for resources
So let’s say I have a piece of code like this:
try{
XXX.close();
YYY.close();
}catch (Exception e)
{
...
}
Copy the code
You are advised to change the value to:
try{ XXX.close(); }catch (Exception e) { ... }try{ YYY.close(); }catch (Exception e) { ... }
Copy the code
It’s a hassle, but it avoids resource leaks. We think, if there is no modified code, in case XXX.close() throw exception, then into the CATH block, YYy. close() will not execute, YYY this resource will not be recycled, has been occupied, such code is likely to cause resource handle leakage. This ensures that XXX and YYY will be closed no matter what.