Most developers believe that performance optimization is a relatively complex issue and requires a lot of experience and knowledge. Yes, there is nothing wrong with that. Admittedly, optimizing your application for the best performance is not an easy task, but that doesn't mean you can't do anything without gaining this experience and knowledge. Here are a few easy-to-follow tips and best practices that can help you create a well-performing application.
Most of these suggestions are Java-based, but not necessarily, and some can be applied to all applications and programming languages. Before we share Java-based performance tuning tips, let's discuss these general performance tuning tips.
1. Do not optimize before necessary
This is probably one of the most important performance tuning tips. You should follow common best practices and try to implement your use cases effectively. But that doesn't mean replacing any standard library or building complex optimizations before proving that it is necessary.
In most cases, premature optimization takes up a lot of time, making the code difficult to read and maintain. Worse, these optimizations usually don't bring any benefits because you spend a lot of time optimizing non-critical parts of your application.
So, how do you prove that you need to optimize something?
First, you need to determine the speed of your application code, for example, specifying a maximum response time for all API calls, or specifying the number of records to be imported over a specific time range. Once done, you can measure which parts of the application are too slow to improve. After doing this, then continue to look at the second tuning tip.
2. Use the analyzer to find the real bottleneck
After you follow the first piece of advice and determine that some parts of your application do need improvement, ask yourself where to start?
You can solve this problem in two ways:
As for why the second method should always be followed.
The answer should be obvious, and the analyzer-based approach will allow you to better understand the performance of your code and allow you to focus on the most critical parts. If you've ever used a parser, you'll be surprised at which parts of the code cause performance issues. However, many times, your first guess will lead you in the wrong direction.
3. Create a performance test suite for the entire application
This is another general trick to help you avoid many unexpected problems that often occur after performance improvements are deployed to a production environment. You should often define a performance test suite that tests the entire application and run it before and after you complete the performance improvement.
These additional test runs will help you identify the functional and performance impact of the change and make sure you don't release an update that does more harm than good. This is especially important if your tasks run on multiple different parts of the application, such as a database or cache.
4. First solve the biggest bottleneck problem
After creating the test suite and using the analyzer to analyze the application, you have a list of questions that need to improve performance, which is great, but it still doesn't answer the question where you should start. You can start with those that can be done quickly, or start with the most important questions.
Of course the former is very tempting because it will produce results soon. Sometimes, it may be necessary to convince other team members or your management that performance analysis is worth it.
But overall, I suggest starting with the most important performance issues first. This will give you the greatest performance improvements, and you may only need to fix a few of these issues to solve your performance needs.
After understanding general performance tuning techniques, let's take a closer look at some Java-specific tuning techniques.
5. Use StringBuilder to programmatically connect strings
There are many different options for connecting strings in Java. For example, you can use a simple + or + =, an old StringBuffer or StringBuilder.
So, which method should you choose?
The answer depends on the code that connects the string. If you programmatically add new content to a string, for example, in a for loop, you should use StringBuilder. It is easier to use and provides better performance than StringBuffer. But remember that StringBuilder is different from StringBuffer, it is not thread-safe and may not be suitable for all use cases.
You just need to instantiate a new StringBuilder and call the append method to add a new part to the string. After you have added all the parts, you can call the toString() method to retrieve the connection string.
The following code snippet shows a simple example. During each iteration, this loop converts i into a string and adds it to the space of StringBuilder sb, so at the end, this code is written to "this is test0123456789" to the log file.
StringBuilder sb = new StringBuilder("This is a test"); for (int i=0; i<10; i++) { sb.append(i); sb.append(" ");}log.info(sb.toString());As you can see in the code snippet, you can provide the first element of the string for the constructor method. This will create a new StringBuilder with the provided string and 16 additional characters capacity. When you add more characters to the StringBuilder, the JVM will dynamically change the size of the StringBuilder.
If you already know how many characters your string contains, you can provide this number to different constructor methods to instantiate a StringBuilder with defined capacity. This further improves its efficiency because it does not require dynamically expanding its capacity.
6. Use +Connection String in Declaration
When you implement your first application in Java, someone may be telling you that you should not use + to concatenate strings. This is correct if you connect the string in the application logic. Strings are immutable, and the result of each string concatenation is stored in a new string object. This requires extra memory and slows down the application, especially when concatenating multiple strings in a loop.
In these cases you should follow tip 5 and use StringBuilder.
But if you just break a string into multiple lines to improve the readability of your code, that's not the case.
Query q = em.createQuery("SELECT a.id, a.firstName, a.lastName "+ "FROM Author a "+ "WHERE a.id = :id");In these cases, you should use a simple + to concatenate your string. The Java compiler will optimize it and perform connections at compile time. Therefore, at runtime, the code only uses 1 character and does not require concatenation.
7. Use basic data types as much as possible
Another quick way to avoid overhead, and to improve application performance is to use primitive data types instead of their wrapper classes. Therefore, it is better to use int instead of Integer, or double instead of double. This will let the JVM store the value on the stack to reduce memory consumption and handle it more efficiently.
8. Try to avoid BigInteger and BigDecimal
Since we have discussed data types, let's look at BigInteger and BigDecimal. The latter, in particular, is popular because of its high precision. But there is a price.
BigInteger and BigDecimal require more memory than simple long or double and greatly reduce all computation speed. So if you need extra precision, or your numbers are beyond a long range, it's best to think twice before doing it. This is probably the only place you need to change in your performance improvement problem, especially when you are implementing a mathematical algorithm.
9. First check the current log level
This suggestion is obvious, but unfortunately, you will find that many codes ignore it. Before creating a debug message, you should check the current log level first.
Here are two examples to illustrate that you shouldn't do this.
// don't do thislog.debug("User [" + userName + "] called method X with [" + i + "]");// or thislog.debug(String.format("User [%s] called method X with [%d]", userName, i));In both cases, you will perform all the steps you need to create the log message without knowing whether the log framework uses the log message. Before creating a debug message, it is best to check the current log level first.
10. Use Apache Commons StringUtils.Replace instead of String.replace
Generally speaking, the String.replace method works well and is very efficient, especially if you are using Java 9. However, if the application requires a lot of replacement operations and you haven't updated to the latest Java version, it still makes sense to check for faster and more efficient alternatives.
One candidate is the Apache Commons Lang's StringUtils.replace method. As Lukas Eder described in a recent blog post, it greatly outweighs the String.replace method of Java 8.
It only requires a small change. You just need to add a Maven dependency to your app pom.xml for the Apache's Commons Lang project and replace all calls to String.replace methods with StringUtils.replace methods.
// replace thistest.replace("test", "simple test");// with thisStringUtils.replace(test, "test", "simple test");11. Cache expensive resources, such as database connections
Caching is a popular solution to avoid repeated execution of expensive or frequently used code snippets. The general idea is simple: it is much cheaper to reuse these resources than to create a new resource again and again.
A typical example is cache database connections in a pool. Creating a new connection takes time and can be avoided if an existing connection is reused.
Other examples can also be found in the Java language itself. For example, the valueOf method of the Integer class caches values between -128 and 127. You might say that creating a new integer is not too expensive, but it is often used, and caching the most commonly used values provides performance benefits.
But when you think about caching, remember that cache implementations can also incur overhead. You need to spend extra memory to store reusable resources, so you may need to manage your cache to enable resources to access or delete outdated resources.
So, before you start caching any resources, make sure to use them frequently.
Summarize
As you can see, improving the performance of your application sometimes does not require a lot of work. Most of the suggestions in this article actually require a little effort to apply them to the code.
But the most important advice is that it is very programming language-independent:
Original link: 11 Simple Java Performance Tuning Tips (Editor/Wei Wei)