Notes_Java performance optimization

[Code optimization details]

1. Try to specify methods and classes as final. The
Java compiler will look for opportunities to inline all final methods. Inlining has a significant effect on the efficiency of Java operations.
For example, in the Java core API, java.lang.string is a final class.
The final modification class, the class cannot be inherited; the final modification method, the method cannot be overridden.

2. Try to reuse objects

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 internal variables whenever 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 and instance variables, 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

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 calling the method, and restoring the scene when the method is called. So for example the following operation:

for (int i = 0; i < list.size; i++){...}

//建议替换为:

for (int i = 0, int length = list.size; i < length; i++){...}

//这样,在list.size很大的时候,就减少了很多的消耗

6. Try to use lazy loading and create when needed

//例如:

String str = "aaa";
if (i == 1){
	list.add(str);
}

//建议替换为:

if(i == 1){
	String str = "aaa";
	list.add(str);
}

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.

8. Don't use try, cacth in the loop

If unavoidable, an error flag is returned and processed externally.

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// By default, 16 characters are allocated

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

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

The initial capacity can be set through the class (not just 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 StringBuilder reaches its maximum capacity, it will increase its capacity to 2 times its current capacity and add 2. Whenever StringBuilder reaches its maximum capacity, it will have 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 power of 2 closest to 5000 is 4096, regardless of the increase of 2 for each expansion, then:

(1) On the basis of 4096, apply for 8194 character arrays, which is equivalent to applying for 12290 character arrays at one time. If you can specify 5000 character arrays at the beginning, it will save more than double Space;

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

In this way, both memory space is wasted and the code running efficiency is reduced. Therefore, it is not wrong to set a reasonable initial capacity for the collection and tool classes implemented by arrays 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 only connecting 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. Try to use System.arraycopy () instead of looping to copy arrays

System.arraycopy() is much faster than copying arrays through loops

11. Multiplication and division use shift operations

//例如

for (val = 0; val < 100000; val += 5){
	a = val * 8;b = val / 2;
}

//用移位操作可以极大地提高性能,因为在计算机底层,对位的操作是最方便、最快的,因此建议修改为:
for (val = 0; val < 100000; val += 5){
	a = val << 3;b = val >> 1;
}

//移位操作虽然快,但是可能会使代码不太好理解,因此最好加上相应的注释。

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

//例如

for (int i = 1; i <= count; i++){
	Object obj = new Object;
}

//这种做法会导致内存中有count份Object对象引用存在,count很大的话,就耗费内存了,建议为改为:

Object obj = null;
for (int i = 0; i <= count; i++) {
	obj = new Object; 
}

//这样的话,内存中只有一份Object对象引用,每次new Object的时候,Object对象引用指向不同的Object罢了,但是内存中只有一份,这样就大大节省了内存空间了。

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

Array is the most efficient, but its capacity is fixed and cannot be changed dynamically. The capacity of ArrayList can grow dynamically, but efficiency is sacrificed.

14. Use HashMap, ArrayList, StringBuilder as much as possible, unless thread safety is required, it is not recommended to use Hashtable, Vector, StringBuffer, the latter three due to the use of synchronization mechanism caused performance overhead

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 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:

public class A{ private static B b = new B;}

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, the operating system will transfer part of the data to the disk. The application server may also dump some inactive sessions to the disk according to the MRU (Most Frequently Used) 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 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:

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 the foreach loop is the iterator, so the second half sentence "conversely, if it is accessed sequentially, it will be more efficient to use iterator" means that the class instances that are accessed sequentially, use the foreach loop to traverse.

20. Use synchronous code blocks instead of synchronous methods

This point has been explained very clearly in the article Synchronized lock method block in the 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 the constants in uppercase can also easily distinguish constants and variables

22. Do not create some unused objects, do not 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

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 does not care how long it takes to start the project on the peer.

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. Use ArrayList for scenarios with more sequential insertion and random access, and LinkedList for scenarios with more element deletion and intermediate insertion

One is a linear table and the other is a linked list. In a word, try to use ArrayList for random queries. ArrayList is better than LinkedList. LinkedList also needs to move pointers. Adding and deleting operations LinkedList is better than ArrayList. ArrayList also needs to move data. But this is a theoretical analysis. , The fact may not be the case, it is important to understand the data structure of the two and prescribe the right medicine.

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 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 (more than 4) 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

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

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

String str = "123";
if (str.equals("123")) {...}

// 建议修改为:

String str = "123";
if ("123".equals(str)){...}

// 这么做主要是可以避免空指针异常

29.i == 1
There is no difference between if (i == 1) and if (1 == i) in java

In case the programmer is not careful, write "if (i == 1)" as "if (i = 1)", then there is a problem. Set i to 1 in the if, and if judges that the content inside is not 0, it returns true, but it is clear that i is 2, and the comparison value is 1, which should return false. This situation is 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:

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 out the first time, because we can assign i to a variable, but 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)" have no difference in semantics, it is better to use the former in terms of reading habits.

30. Do not use toString method on arrays

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

public static void main(String args){ 
	int is = new int{1, 2, 3};
	System.out.println(is.toString);
}

结果是:

[I@18a992f

The original 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 out of range

This will never get the desired result:

public static void main(String args){ 
	long l = 12345678901234L;
	int i = (int)l;
	System.out.println(i);
}

// 我们可能期望得到其中的某几位,但是结果却是:1942892530

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

Int data type is a four-byte 32-bit, taken from above the lower string of binary data, the first 32 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 = 12345678901234 L , 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, write "float f = 3.5 f "

(2). Writing 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 have the 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 :

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");

}

// 运行结果为:

String.valueOf:11ms Integer.toString:5ms i + "":25ms

Therefore, when a basic data type is converted 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. Not to mention 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. In general, what we need is to traverse the Key and Value in the Map. Then the recommended and most efficient way is:

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, then use "Set keySet = hm.keySet;" will be more appropriate

35. Separate operations are recommended for resource close

Meaning, for example, such a piece of code:

try{XXX.close;YYY.close;}catch (Exception e){...}

// 建议修改为:

try{ XXX.close; }catch (Exception e) { ... }try{ YYY.close; }catch (Exception e) { ... }

Although a little troublesome, it can avoid resource leakage. 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 has been occupied. Such a code Many, it may cause resource handle leakage. After changing to the above wording, it is guaranteed that XXX and YYY will be closed anyway.

36. Try not to use finalize method

In fact, it is a very bad choice to put the resource cleanup in the finalize method. Because the workload of GC is very large, most applications will be suspended, so choosing to use the finalize method for resource cleanup will cause a greater burden on the GC. , The program runs more efficiently.

37. Try to avoid using two-dimensional arrays.
Two-dimensional data occupies much more memory space than one-dimensional arrays, probably more than 10 times.

38. Try to avoid split

Unless it is necessary, you should avoid using split. Split is relatively inefficient because it supports regular expressions. If it is frequent dozens of calls, millions of calls will consume a lot of resources. If you really need to call split frequently, you can Consider using apache's StringUtils.split(string,char), the results of frequent splits can be cached.

39. In the development of java+Oracle application system, the SQL language embedded in java should be capitalized as much as possible to reduce the analysis burden of the Oracle parser.

40. Avoid enumeration, the use of floating point numbers.

41. Make the getter/setter methods for accessing variables in the instance become "final"

A simple getter/setter method should be set to final, which will tell the compiler that this method will not be overloaded, so it can become "inlined", for example:

class MAF {
	private int _size;
	public void setSize (int size) {
	_size = size;
	}
}

// 更正:

class DAF_fixed {
	final public void setSize (int size) {
		_size = size;
	}
	private int _size;
}

42. For constant strings, use 'String' instead of 'StringBuffer'

Constant strings do not need to change the length dynamically.

43. When adding strings, use '' instead of "", if the string has only one character

public class STR {
	public void method(String s) {
		String string = s + "d" // violation.
		string = "abc" + "d" // violation.
	}
}

// 更正:

// 将一个字符的字符串替换成' '

public class STR {
	public void method(String s) {
		String string = s + 'd'
		string = "abc" + 'd'
	}
}

[Note: Most of the above content is compiled and extracted from the Internet, mainly for my own knowledge accumulation]

Guess you like

Origin blog.csdn.net/weixin_42547014/article/details/110489121