preface

A code optimization article: conditional statement multi-layer nested problem optimization, help you write code that does not let colleagues ridicule!

Today I would like to share some common code optimization techniques in my daily work. I hope it will be helpful to you!

The article was first published on an official account (Yuebanfeiyu), and then synchronized to the personal website: xiaoflyfish.cn/

Feel there is harvest, hope to help like, forward ha, thank you, thank you

The body of the

The visibility of class members and methods is minimized

For example, if it is a private method, delete it if you want

If a public service method, or a public member variable, is deleted without much thought.

Use displacement operations instead of multiplication and division

Computers are represented in binary, and displacement greatly improves performance.

<< to the left is the same thing as multiplying by 2; >> To the right is the same thing as dividing by 2;

>>> Unsigned right shift is the same as dividing by 2, but it ignores the sign bit and fills the space with 0.

a = val << 3;
b = val >> 1;
Copy the code

Minimize double counting of variables

We know that method calls have costs, including creating stack frames, protecting the scene while calling the method, restoring the scene, and so on.

/ /
for (int i = 0; i < list.size(); i++) {
  System.out.println("result");
}

/ / is
for (int i = 0, length = list.size(); i < length; i++) {
  System.out.println("result");
}
Copy the code

When list.size() is very large, it reduces a lot of consumption.

Do not catch RuntimeException

Runtimeexceptions should not be caught by catch statements, but should be circumvented using coding.

The list may get an array out of bounds exception as shown in the following code.

Transgressions can be determined in advance by code, rather than catching exceptions when they occur.

The code will be more elegant and efficient if you judge this way ahead of time.

public String test1(List<String> list, int index) {
    try {
        return list.get(index);
    } catch (IndexOutOfBoundsException ex) {
        return null; }}/ / is
public String test2(List<String> list, int index) {
    if (index >= list.size() || index < 0) {
        return null;
    }
    return list.get(index);
}
Copy the code

Use local variables to avoid allocation on the heap

Since the heap resource is shared by multiple threads and is the main area where the garbage collector works, too many objects can cause GC stress and variables can be allocated on the stack by means of local variables. In this way variables are destroyed as the method completes execution, reducing the pressure on the GC.

Reduce the scope of variables

Pay attention to the scope of variables and minimize object creation.

In the following code, the variable S is created each time it enters the method and can be moved inside the if statement.

public void test(String str) {
    final int s = 100;
    if(! StringUtils.isEmpty(str)) {intresult = s * s; }}Copy the code

Try to use a lazy loading strategy and create it when you need it

String str = "Moon with Flying Fish.";
if (name == "Public Account") {
  list.add(str);
}

if (name == "Public Account") {
  String str = "Moon with Flying Fish.";
  list.add(str);
}
Copy the code

Access static variables directly using the class name

Using an object to access a static variable is an extra step of addressing by first finding the class for the variable and then finding the variable for the class.

 / /
int i = objectA.staticMethod();
 / / is
int i = ClassA.staticMethod();
Copy the code

String concatenation uses StringBuilder

String concatenation, use StringBuilder or StringBuffer, do not use the + sign.

/ /
public class StringTest {
    @Test
    public void testStringPlus(a) {
        String str = "111";
        str += "222";
        str += "333"; System.out.println(str); }}/ / is
public class TestMain {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("111");
        sb.append("222");
        sb.append(333); System.out.println(sb.toString()); }}Copy the code

Overrides the object’s HashCode rather than simply returning a fixed value

Some students developed overwriting HashCode and Equals methods to return HashCode to a fixed 0, which was not appropriate

When these objects are stored in a HashMap, performance is very low because the HashMap uses HashCode to locate the Hash slot. When there is a conflict, the nodes are organized using a linked list or red-black tree, which returns a fixed zero, effectively disabling Hash addressing.

When a collection such as HashMap is initialized, the initial value size is specified

There are many such objects, such as ArrayList, StringBuilder, and so on. Specifying the initial value size can reduce the performance penalty caused by capacity expansion.

For calculation of initial value, please refer to Alibaba Development Manual:

Do not keep creating object references within the loop

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

/ / is
Object obj = null;
for (int i = 0; i <= size; i++) {
    obj = new Object();
}
Copy the code

The first method will result in the existence of size Object references in memory. If the size is too large, it will consume memory

When traversing a Map, use the EntrySet method

With EntrySet, you can return a set object and use it directly. The KeySet method obtains a set of keys, which requires another GET operation. Therefore, EntrySet is recommended to traverse the Map.

Set<Map.Entry<String, String>> entryseSet = nmap.entrySet();
for (Map.Entry<String, String> entry : entryseSet) {
    System.out.println(entry.getKey()+","+entry.getValue());
}
Copy the code

Do not use the same Random in multiple threads

The seed of the Random class can compete in the case of concurrent access, resulting in performance degradation. It is recommended to use the ThreadLocalRandom class in a multi-threaded environment.

 public static void main(String[] args) {
        ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();
        Thread thread1 = new Thread(()->{
            for (int i=0; i<10; i++){ System.out.println("Thread1:"+threadLocalRandom.nextInt(10)); }}); Thread thread2 =new Thread(()->{
            for (int i=0; i<10; i++){ System.out.println("Thread2:"+threadLocalRandom.nextInt(10)); }}); thread1.start(); thread2.start(); }Copy the code

LongAddr is recommended for self-increment

Auto-increment can control thread-safety through a combination of synchronized and volatile, or atomic classes (such as AtomicLong) can be used.

The latter is faster than the former, AtomicLong uses CAS for comparison replacement, which can cause too much invalid spin in the case of too many threads. You can use LongAdder to replace AtomicLong for further performance improvement.

public class Test {
    public int longAdderTest(Blackhole blackhole) throws InterruptedException {
        LongAdder longAdder = new LongAdder();
        for (int i = 0; i < 1024; i++) {
            longAdder.add(1);
        }
        returnlongAdder.intValue(); }}Copy the code

Use less reflection in your program

Reflection is powerful, but it is implemented by parsing bytecodes, and performance is less than ideal.

There are many ways to optimize reflection, such as caching the process of reflection execution (such as Method) and using reuse to speed up reflection.

After Java 7.0, a new package java.lang.invoke was added, along with a new JVM bytecode instruction invokeDynamic, which supports invocation of target methods directly from a string at the JVM level.

The last

Feel there is harvest, hope to help like, forward ha, thank you, thank you

Wechat search: month with flying fish, make a friend, into the interview exchange group