You will have learned by the end of this article
- 11 Java Code Performance Optimization tips to Learn
1. Introduction
When developing any Java application, we talk about optimization — the concept of optimization. As developers, we should make sure that the code we write is as clean and bug-free as possible, and consider performance issues as much as possible.
To that end, I’ve compiled the following 11 Java code performance optimization tips that you’re sure to use.
2. 11 Optimization tips
2.1 Avoid too long method
When we define a method, we should consider that a method should not be too long, it should be specialized to perform a single function. This is actually good for maintenance and performance.
On the one hand, from a maintenance perspective, methods of appropriate length are more readable and easier to understand; On the other hand, during class loading and method invocation, methods are loaded into memory. If a method is too large, processing will consume additional memory and CPU cycles. We should learn to break down a long method at the right logical point.
2.2 Avoid multiple IF-else statements
You should be familiar with this optimization point. But actually when you’re writing code, you’re going to do if-else all the way through.
Doing so can actually affect performance. Because the JVM must compare conditions. The situation gets worse if you use the same conditions in loops like for, while, and so on.
If we have a lot of conditions in our business logic, we can try to group the conditions and return a Boolean value, which we can then use in an if statement.
Alternatively, if possible, we can consider using switch statements instead of multiple if-else statements. Switch statements have performance advantages over if-else statements. Here’s an example:
if (condition1) { if (condition2) { if (condition3 || condition4) { execute .. } else { execute.. }Copy the code
In contrast to the above code, the appropriate action would be as follows:
boolean result = (condition1 && condition2) && (condition3 || condition4)
Copy the code
2.3 Avoid using Iterator
Writing loops in Java5’s foreach style is really easy and concise, and it looks cool!
But sometimes being cool comes at the cost of performance.
Such as:
for (String str: strs) {
. . .
}
Copy the code
Each time you run the code, if STRS is Iterable, you will create a new Iterator object. Doing so will result in more memory consumption.
If you are looking for extreme performance, you are advised to use the original script:
int size = strs.size(); for (int i = 0; i < size; i++) { String value = strs.get(i); ...}Copy the code
2.4 Avoid retrieving size in collections
When iterating over any collection, get the size of the collection beforehand, not during the iteration — this avoids multiple calls to the size() method.
Here’s an example:
List<String> eleList = getData(); for (int i = 0; i < eleList.size(); i++) { execute code .. }Copy the code
In contrast to the above code, the appropriate action would be as follows:
List<String> objList = getData(); int size = objList.size(); for (int i = 0; i < size; i++) { execute code .. }Copy the code
2.5 Avoid Using+
Number concatenation string
From JDK5 onwards, the Java compiler has been optimized to concatenate strings with + signs, which the compiler actually automatically optimizes to use StringBuilder when compiled.
And String is final, so objects created with String cannot be reused. Therefore, if we need continuous concatenation, concatenating strings with a + sign will result in the creation of multiple Strings, which will consume more heap memory.
In general, when strings are small, the + sign is as efficient as StringBuilder concatenation; But when it comes to single-threaded loop concatenation, it’s best to use StringBuilder for performance optimization.
Here’s an example:
String str = "sample";
for (int i = 0; i < count; i++) {
str = str + "-" + i;
}
Copy the code
A more appropriate course of action is as follows:
StringBuilder stringBuilder = new StringBuilder("sample");
for (int i = 0; i < count; i++) {
stringBuilder.append("-");
stringBuilder.append(i);
}
Copy the code
2.6 Use basic types whenever possible
Because base types are stored in stack memory, objects are stored in heap memory. If possible, we should use primitive types instead of objects because stack memory is faster to access than heap memory.
So in some cases, to define a variable or an array, we can use int instead of Integer,double instead of double.
2.7 Avoid using BigDecimal classes
The BigDecimal class provides precise small values, and overuse of this object can have an impact on performance, especially if it is used to calculate certain values in loops.
BigDecimal takes up more memory for computation than long or double. If the precision is not limited, or if we are sure that the range of evaluated values is not beyond long or double, we can avoid BigDecimal and use long or double instead, with appropriate conversions.
2.8 Avoid creating “expensive” objects too often
There are classes that hold data in the application, and these objects are expensive to create and should be avoided multiple times.
For example, a database connection object, a system configuration object, or a session object for a user login. These objects consume a lot of resources when they are created, and we should choose to reuse them rather than create them again.
For these “expensive” objects, we use the singleton pattern to create a single instance whenever possible and reuse it where necessary.
2.9 Use preparedStatements instead of statements
SQL queries using the JDBC API are probably less common these days, but I thought it was worth taking a look.
PreparedStatement has an advantage over Statement for parameterized queries because the PreparedStatement object is compiled once and executed multiple times. The Statement object is compiled and executed each time it is called.
In addition, PreparedStatement objects are secure from SQL injection attacks.
2.10 Avoid unnecessary log statements and incorrect log levels
This advice should be common, but a lot of code ignores it. When creating debug information, we should first check the current log level.
Otherwise you may inadvertently create a useless log message. Take an example:
log.debug("User [" + userName + "] called method X with [" + i + "]");
log.debug(String.format("User [%s] called method X with [%d]", userName, i));
Copy the code
In this case, we need to do all the necessary steps to create the log information, without knowing whether the program will ever use it.
Furthermore, what if the creation of this log information involves more resource usage?
So it is a good idea to check the current log level, as follows:
if(log.isDebugEnabled()) {
log.debug("User [" + userName + " ] called method X with [" + i + "] ");
}
Copy the code
2.11 Select Required Fields in an SQL query
Sometimes, we need to write SQL to get data. At this point we should avoid selecting all database columns and select only the database columns we need.
Selecting too many columns can cause delays in database query execution and increase network traffic.
Take an example:
select * from books where book_id = 6;
Copy the code
To this, I suggest writing:
select book_title, book_desc, book_price from books where book_id = 6;
Copy the code
3. The conclusion
Many people think that performance tuning is a complex topic that requires a lot of experience and knowledge, and to some extent this is true.
It’s not easy to develop an application and expect the best possible performance. But even if you’re not a performance tuning expert, there are some simple steps you can take to improve performance.
If you’re still wondering here, take a look at some of my other posts:
- How many new features do you know about # Java8-15?
- # From the star of open source entrepreneurship to making bombs, and finally deleting libraries and running away, what has he experienced?
- # [2021] Neither wind nor rain — three years in the industry, starting again
Thanks for watching yijun@Monday Radio. If you feel good, quickly give me three support, let’s next period see each other.