Most developers take for granted that performance optimization is complex and requires a lot of experience and knowledge. Well, you can't say it's completely wrong. Optimizing your application for optimal performance is not an easy task. But that doesn't mean that if you don't have the knowledge, you can't do anything. Here are 11 easy-to-follow recommendations and best practices to help you create a well-performing application.
Most of the recommendations are for Java. However, there are several recommendations that are language-independent and can be applied to all applications and programming languages. Before discussing performance tuning techniques specifically for Java, let's take a look at common techniques.
1. Do not optimize before you know it is necessary
This may be one of the most important performance tuning techniques. You should follow common best practices and try to implement the use cases efficiently. However, this does not mean that you should replace any standard library or build complex optimizations before you prove necessary.
In most cases, premature optimization takes a lot of time and makes the code difficult to read and maintain. To make matters worse, these optimizations usually do not bring any benefit, because you spend a lot of time optimizing the non-critical parts of your application.
So, how do you prove that you need to optimize something?
First, you need to define how quickly your application code is, for example, specifying the maximum response time for all API calls, or specifying the number of records to import in a specific time range. After you've done this, you can measure which parts of your application are too slow to be improved. Then, look at the second trick.
2. Using analyzers to find real bottlenecks
After you have followed the first recommendation and determined that some parts of the application need improvement, where do you start?
You can solve the problem in two ways:
- Review your code and start with a section that looks suspicious or that you think might be problematic.
- Or use the parser and get detailed information about the behavior and performance of each part of the code.
I hope you don't need me to explain why you should always follow the second method.
Obviously, a parser-based approach can give you a better understanding of the performance impact of your code and enable you to focus on the most critical parts. If you've ever used a profiler, you must remember how surprised you were to find out what parts of the code were having a performance problem. To be honest, my first guess led me to go the wrong way more than once.
3. Create a performance test suite for the entire application
This is another common technique that can help you avoid many of the unexpected problems that often occur after you deploy performance improvements to production. You should always define a performance test suite that tests the entire application and run it before and after performance improvements.
These additional test runs will help you identify the functional and performance side effects of the changes and ensure that the updates do not cause more harm than beneficial. This is especially important if you work on components that are used by several different parts of your application, such as databases or caches.
4. First deal with the biggest bottleneck
After you have created the test suite and analyzed the application using the parser, you can list a series of issues that need to be addressed to improve performance. It's good, but it still can't answer the question where you should start. You can focus on quick-impact solutions or start with the most important questions.
Quick-impact programmes can be very attractive at first because you can quickly show the first result. But sometimes you may need to convince other team members or management that performance analysis is worth it-because you can't see the effect for the time being.
But overall, I recommend dealing with the most important performance issues first. This will provide you with the greatest performance improvements and may no longer need to address some of these issues in order to meet your performance needs.
This is the end of common performance tuning techniques. Let's take a closer look at some Java-specific tricks.
5. Connect a string programmatically using StringBuilder
There are a number of different options to concatenate strings in Java. For example, you can use simple + or + =, as well as StringBuffer or StringBuilder.
So, which method should you choose?
The answer depends on the code that connects the string. If you are adding new content programmatically to a string, for example in a for loop, then you should use StringBuilder. It is easy to use and offers better performance than StringBuffer. Keep in mind, however, that StringBuilder is not thread-safe compared to stringbuffer, 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 concatenated string.
The following code snippet shows a simple example. During each iteration, the loop converts I to a string and adds it to the StringBuilder SB with a space. So, finally, this code will be written in the log file "This is a Test0 1 2 3 4 5 6 7 8 9".
New StringBuilder ("This is a Test"); For (int i=0; i<; i++) { sb.append (i); Sb.append ("");} Log.info (sb.tostring ());
As you see in the code snippet, you can provide the first element of the string to a constructor method. This creates a new StringBuilder, and the new StringBuilder contains the capacity of the provided string and 16 extra characters. When you add more characters to StringBuilder, the JVM dynamically increases the size of the StringBuilder.
If you already know how many characters your string will contain, you can give that number to a different construction method to instantiate a StringBuilder with a defined capacity. This further increases efficiency because it does not need to dynamically scale its capacity.
6. Use + to connect a string in a statement
When you implement your first application in Java, someone might have told you that you shouldn't use + to connect to a string. This is true if you are connecting strings in the application logic. The string is immutable, and the connection results for each string are stored in a new string object. This requires additional memory and slows down your application, especially if you are connecting multiple strings within a loop.
In these cases, you should follow Tip 5 and use StringBuilder.
However, if you just split the string into multiple lines to improve the readability of the code, the situation is different.
Query q = em.createquery ("select a.ID, A.firstname, a.lastname" + "fromAuthor a" + "WHERE a.id =:id");
In these cases, you should use a simple + to connect your string. The Java compiler optimizes this and performs a connection at compile time. So, at run time, your code will only use 1 strings, no connection required.
7. Use primitives whenever possible
Another easy and quick way to avoid any overhead and improve application performance is to use the base type instead of its wrapper class. Therefore, it is better to use int instead of integer and double instead of double. This allows the JVM to store values in the stack instead of the heap to reduce memory consumption and to make more efficient processing.
8. Try to avoid BigInteger and BigDecimal
Now that we're talking about data types, let's take a quick look at BigInteger and BigDecimal. The latter, in particular, are welcomed by the people for their accuracy. But there is a price to it.
BigInteger and BigDecimal require more memory than a simple long or double, and will significantly slow down all calculations. So, if you need extra precision, or the number will exceed the range of long, then you'd better think twice. This is probably the only way you need to change to solve performance problems, especially when implementing mathematical algorithms.
9. Check the current log level first
This advice should be obvious, but unfortunately many programmers tend to ignore it when writing code. Before you create a debug message, you should always check the current log level first. Otherwise, you might create a log message string that will then be ignored.
Here are two examples of the opposite.
with ["+ i +"] "); //or Thislog.debug (with[%d] ", userName, i));
In both cases, you will perform all the necessary steps to create a log message without knowing whether the log framework will use log messages. Therefore, it is a good idea to check the current log level before creating a debug message.
Do theif (log.isdebugenabled ()) { log.debug ("User [" + UserName + "] called method X with [" + i + "]" );}
10. UseApache Commons stringutils.replace instead of String.Replace
In general, the String.Replace method works well and is highly efficient, especially in the case of Java 9. However, if your application requires a large number of substitutions and is not updated to the latest Java version, then it is still necessary to find a faster and more efficient alternative.
One alternative answer is Apache Commons Lang's Stringutils.replace method. As Lukas Eder in his recent blog post, Stringutils.replace method is far better than the String.Replace method of Java 8.
And it just needs a little change. That is, add the Maven dependency of the Apache Commons Lang project to the application Pom.xml and replace all calls to the String.Replace method with the Stringutils.replace method.
Replace Thistest.replace ("test");//With Thisstringutils.replace (test, "test");
11. Cache expensive resources, such as database connections
Caching is a popular solution to avoid repetitive execution of expensive or frequently used code snippets. The general idea is simple: reusing these resources is cheaper than creating new resources over and over again.
A typical example is the database connection in the cache pool. The creation of a new connection takes time, and if you reuse an existing connection, you can avoid this situation.
You can also find other examples in the Java language itself. For example, the valueof method of the integer class caches a value between 128 and 127. You might say that creating a new integer is not too expensive, but because it is often used, caching the most commonly used values can also provide performance benefits.
However, when you consider caching, keep in mind that caching implementations also incur overhead. You need to spend extra memory to store reusable resources, so you might need to manage the cache to make resources accessible and delete obsolete resources.
So before you start caching any resources, make sure that the cache is worthwhile, which means that you must use them enough.
Summarize
As you can see, there are times when you don't need too much work to improve the performance of your application. Most of the recommendations in this article only require a little effort to apply them to your code.
But the most important ones are those that have nothing to do with programming languages:
- Don't optimize until you know it's necessary.
- Using analyzers to find real bottlenecks
- Tackle the biggest bottlenecks first
Welcome to join the Learning Exchange Group 569772982, we learn to communicate together .
11 Simple Java Performance Tuning tips