How to implement code optimization in JAVA (technical explanation)

Foreword: Today, senior Ye Qiu talks to you about the topic of optimization, so let's talk about how to implement code optimization in Java. Here are some practical tips to share with you, I hope it will be helpful to you.

 Blogger Portal:

  Senior Ye Qiu

Recommended column:

Autumn recruitment interview questions

Understanding Vue

Spring series

Spring Boot series

Cloud Native Series (paid column)


Table of contents

1. Concatenate strings with String.format

2. Create a bufferable IO stream

3. Reduce the number of cycles

4. Remember to close in time when you run out of resources

5. Use pool technology

1. Concatenate strings with String.format

I don't know if you have spliced ​​strings, especially in the case of multiple parameters and long strings.

For example, there is a requirement now: to use a get request to call a third-party interface, multiple parameters need to be spliced ​​after the url.

Previously our request address was spliced ​​like this:

String url = "http://susan.sc.cn?userName="+userName+"&age="+age+"&address="+address+"&sex="+sex+"&roledId="+roleId;

Strings +are concatenated with numbers, which is very error-prone.

StringBuilderIt was optimized later, and the concatenated string was used instead :

StringBuilder urlBuilder = new StringBuilder("http://susan.sc.cn?");
urlBuilder.append("userName=")
.append(userName)
.append("&age=")
.append(age)
.append("&address=")
.append(address)
.append("&sex=")
.append(sex)
.append("&roledId=")
.append(roledId);

After the code is optimized, it is a little more intuitive.

But it still looks awkward.

At this time, you can use String.formatmethod optimization:

String requestUrl = "http://susan.sc.cn?userName=%s&age=%s&address=%s&sex=%s&roledId=%s";
String url = String.format(requestUrl,userName,age,address,sex,roledId);

The readability of the code has improved a lot at once.

We can usually use String.formatmethods to concatenate url request parameters, log printing and other strings.

But it is not recommended to use it to splicing strings in a for loop, because its execution efficiency is slower than using the + sign to splicing strings, or using StringBuilder to splicing strings.

 

2. Create a bufferable IO stream

IO流Presumably everyone uses it a lot. We often need to transfer data to 写入a certain file, or data from a certain file, or 读取even 内存file a, from directory b 复制to directory c, etc.

JDK provides us with a very rich API to operate IO streams.

E.g:

public class IoTest1 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            File srcFile = new File("/Users/dv_susan/Documents/workspace/jump/src/main/java/com/sue/jump/service/test1/1.txt");
            File destFile = new File("/Users/dv_susan/Documents/workspace/jump/src/main/java/com/sue/jump/service/test1/2.txt");
            fis = new FileInputStream(srcFile);
            fos = new FileOutputStream(destFile);
            int len;
            while ((len = fis.read()) != -1) {
                fos.write(len);
            }
            fos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

The main function of this example is to copy the contents of the 1.txt file to the 2.txt file. This example uses ordinary IO streams, which can meet the requirements from a functional point of view, but the performance is not very good.

Because in this example, reading one byte of data from the 1.txt file will immediately write it to the 2.txt file, requiring very frequent reading and writing of the file.

optimization:

public class IoTest {
    public static void main(String[] args) {
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            File srcFile = new File("/Users/dv_susan/Documents/workspace/jump/src/main/java/com/sue/jump/service/test1/1.txt");
            File destFile = new File("/Users/dv_susan/Documents/workspace/jump/src/main/java/com/sue/jump/service/test1/2.txt");
            fis = new FileInputStream(srcFile);
            fos = new FileOutputStream(destFile);
            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);
            byte[] buffer = new byte[1024];
            int len;
            while ((len = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            bos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bos != null) {
                    bos.close();
                }
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (bis != null) {
                    bis.close();
                }
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

This example uses BufferedInputStreamand BufferedOutputStreamcreates 可缓冲input and output streams.

The most critical point is to define a buffer byte array, temporarily save the data read from the 1.txt file, and then write the data of the buffer byte array to 2.txt in batches at one time.

The advantage of this is that it reduces the number of reads and writes to files, and we all know that reading and writing files is a very time-consuming operation. That is to say, the use of cacheable input and output streams can improve the performance of IO, especially when the file is very large, the efficiency will be significantly improved.

3. Reduce the number of cycles

In our daily development, looping through collections is an essential operation.

However, if the loop hierarchy is deep, loops within loops may affect the execution efficiency of the code.

反例:

for(User user: userList) {
   for(Role role: roleList) {
      if(user.getRoleId().equals(role.getId())) {
         user.setRoleName(role.getName());
      }
   }
}

There are two layers of loops in this example. If there is a lot of userList and roleList data, it needs to be traversed many times to get the data we need, which consumes a lot of CPU resources.

正例:

Map<Long, List<Role>> roleMap = roleList.stream().collect(Collectors.groupingBy(Role::getId));
for (User user : userList) {
    List<Role> roles = roleMap.get(user.getRoleId());
    if(CollectionUtils.isNotEmpty(roles)) {
        user.setRoleName(roles.get(0).getName());
    }
}

The easiest way to reduce the number of loops is to change the set of loops in the second layer into map, so that you can directly pass through keyto get the desired valuedata.

Although the key of the map exists , hash冲突traversing the stored data is much smaller than traversing the entire list collection.链表红黑树时间复杂度

4. Remember to close in time when you run out of resources

In our daily development, it may be accessed frequently 资源, such as: getting database connections, reading files, etc.

Let's take getting a database connection as an example.

反例:

//1. 加载驱动类
Class.forName("com.mysql.jdbc.Driver");
//2. 创建连接
Connection connection = DriverManager.getConnection("jdbc:mysql//localhost:3306/db?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8","root","123456");
//3.编写sql
String sql ="select * from user";
//4.创建PreparedStatement
PreparedStatement pstmt = conn.prepareStatement(sql);
//5.获取查询结果
ResultSet rs = pstmt.execteQuery();
while(rs.next()){
   int id = rs.getInt("id");
   String name = rs.getString("name");
}

The above code can run normally, but it has made a big mistake, namely: the resources of ResultSet, PreparedStatement and Connection objects are not closed after use.

We all know that database connections are invaluable resources. It is impossible for us to create a connection all the time, and after it is used up, it will not be recycled, and the database resources will be wasted in vain.

正例:

//1. 加载驱动类
Class.forName("com.mysql.jdbc.Driver");

Connection connection = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
    //2. 创建连接
    connection = DriverManager.getConnection("jdbc:mysql//localhost:3306/db?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8","root","123456");
    //3.编写sql
    String sql ="select * from user";
    //4.创建PreparedStatement
    pstmt = conn.prepareStatement(sql);
    //5.获取查询结果
    rs = pstmt.execteQuery();
    while(rs.next()){
       int id = rs.getInt("id");
       String name = rs.getString("name");
    }
} catch(Exception e) {
  log.error(e.getMessage(),e);
} finally {
   if(rs != null) {
      rs.close();
   }
   
   if(pstmt != null) {
      pstmt.close();
   }
   
   if(connection != null) {
      connection.close();
   }
}

In this example, whether it is a ResultSet, a PreparedStatement, or a Connection object, after use, the closemethod will be called to close the resource.

Here is a warm reminder: ResultSet, or PreparedStatement, or Connection object, the order in which the three close resources cannot be reversed, otherwise an exception may occur.

5. Use pool technology

We all know that to query data from the database, we must first connect to the database and obtain Connectionresources.

To make a program execute in multiple threads, you need to use Threadclasses to create threads, and threads are also a resource.

Usually the process of a database operation is as follows:

  1. Create a connection

  2. perform database operations

  3. close the connection

Creating a connection and closing a connection is a very time-consuming operation. Creating a connection requires creating some resources at the same time. When closing a connection, those resources need to be recycled.

If the program needs to create and close the connection every time the user makes a database request, it may waste a lot of time.

Additionally, excessive database connections may result.

We all know that the database 最大连接数is limited. Taking mysql as an example, the maximum number of connections is: 100, but this number can be adjusted through parameters.

If the number of connections requested by the user exceeds the maximum number of connections, too many connectionsan exception will be reported. If a new request comes in, it will find that the database becomes unavailable.

At this time, you can pass the command:

show variables like max_connections

Check the maximum number of connections.

Then pass the command:

set GLOBAL max_connections=1000

Manually modify the maximum number of connections.

This approach can only temporarily alleviate the problem, it is not a good solution and cannot fundamentally solve the problem.

The biggest problem is: the number of database connections can grow indefinitely and uncontrollably.

At this time we can use 数据库连接池.

The current Java open source database connection pools are:

  • DBCP: is a database connection pool that relies on the Jakarta commons-pool object pool mechanism.

  • C3P0: is an open source JDBC connection pool that is released with Hibernate in the lib directory, including DataSources objects that implement the Connection and Statement pools specified by the jdbc3 and jdbc2 extension specifications.

  • Druid: Alibaba's Druid is not only a database connection pool, but also includes a ProxyDriver, a series of built-in JDBC component libraries, and a SQL Parser.

  • Proxool: It is a Java SQL Driver driver, which provides connection pool encapsulation for other types of selected drivers, which can be easily ported to existing code.

The most used database connection pools are: Druid.

 This issue ends here, pay attention to bloggers and don’t get lost, Senior Ye Qiu will take you on the highway~~

Guess you like

Origin blog.csdn.net/m0_63722685/article/details/126393950