11 Practical Tips for Java Performance Tuning

Date: Oct 25, 2022

Related Tags:1. Install the SDK for Java
2. SDK for Java

Abstract: Most developers consider performance optimization to be a complex problem that requires a lot of experience and knowledge. Yes, there is nothing wrong with that. Granted, optimizing an application for the best performance isn't an easy task, but that doesn't mean you can't do anything without this experience and knowledge. Below are a few easy-to-follow recommendations and best practices that can help you create a well-performing application.

Most developers consider performance optimization to be a complex problem that requires a lot of experience and knowledge. Yes, there is nothing wrong with that. Granted, optimizing an application for the best performance isn't an easy task, but that doesn't mean you can't do anything without this experience and knowledge. Here are a few easy-to-follow recommendations and best practices that will help you create a well-performing application.

Most of these recommendations are Java-based, but not necessarily, some are applicable to all applications and programming languages. Before we share Java-based performance tuning tips, let's discuss these general performance tuning tips.

1. Don't optimize until necessary

This is probably one of the most important performance tuning tips. You should follow common best practices and try to implement your use case efficiently. But that doesn't mean replacing any standard library or building complex optimizations until it's proven necessary.

In most cases, premature optimization takes up a lot of time, making the code hard to read and maintain. To make matters worse, these optimizations usually don't bring any benefit because you spend a lot of time optimizing non-critical parts of your application.

So how do you justify that you need to optimize something?

First, you need to determine the speed of your application code, for example, specify a maximum response time for all API calls, or specify the number of records to import in a specific time frame. Once done, you can measure which parts of the application are too slow and need improvement. When this is done, then move on to the second tuning tip.

2. Use a profiler to find the real bottleneck

After you've followed the first piece of advice and determined that some parts of your application really need improvement, ask yourself where to start?

You can solve this problem in two ways:

You can take a look at your code and start with the part that looks suspicious or you think it might create a problem.
Or use a profiler to get detailed information on the behavior and performance of each part of your code.
As to why the second approach should always be followed.

The answer should be obvious, a profiler-based approach gives you a better understanding of the performance implications of your code and allows you to focus on the most critical parts. If you've ever used a profiler, you'll be surprised what parts of your code are causing performance problems. 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 tip that will help you avoid many unexpected problems that often occur after performance improvements are deployed to production. You should often define a performance test suite that tests your entire application and run it before and after you've made performance improvements.

These additional test runs will help you identify the functional and performance impact of the change, and ensure you don't release an update that does more harm than good. This is especially important if your tasks run on different parts of your application such as databases or caches.

4. Solve the biggest bottleneck first

After creating a test suite and profiling your application with a profiler, you have a list of questions that need to improve performance, which is great, but it still doesn't answer the question of where you should start. You can start with those that can be done quickly, or with the most important issues.

Of course the former is tempting, because it will come to fruition very quickly. At times, it may be necessary to convince other team members or your management that performance analysis is worthwhile.

But in general, I recommend tackling the most important performance issues first. This will give you the biggest performance improvement, and you may only need to fix a few of these issues to address your performance needs.

Now that we understand general performance tuning tips, let's take a closer look at some Java-specific tuning tips.

5. Use StringBuilder to concatenate strings programmatically

There are many different options for connection strings in Java. For example, a simple + or +=, old StringBuffer or StringBuilder can be used.

So, which method should you choose?

The answer depends on the code of the connection 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 keep in mind that StringBuilder, unlike StringBuffer, 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. When 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 StringBuilder sb's space, so at the end, this code writes "this is test0123456789" to the log file.

As you can see in the code snippet, you can provide the constructor method with the first element of the string. This will create a new StringBuilder with the provided string and a capacity for 16 extra characters. As 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, then you can provide this number to the various constructor methods to instantiate a StringBuilder with the defined capacity. This further increases its efficiency as it does not need to dynamically expand its capacity.

6. Use + connection string in declaration

When you implemented your first application in Java, someone probably told you that you shouldn't use + to concatenate strings. This is correct if the strings are concatenated in the application logic. Strings are immutable and the result of each string concatenation is stored in a new string object. This requires additional 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 that's not the case if you're just breaking a string into multiple lines to improve the readability of your code.

In these cases, you should concatenate your strings with a simple +. The Java compiler will optimize it and perform the linking at compile time. So, at runtime, the code only uses 1 character and no concatenation is required.

7. Use basic data types as much as possible

Another quick way to avoid overhead and improve application performance is to use primitive data types instead of their wrapper classes. So it's 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 process it more efficiently.

8. Try to avoid BigInteger and BigDecimal

Since we've discussed data types, let's look at BigInteger and BigDecimal again. The latter, in particular, is popular due to its high precision. But this comes at a price.
BigInteger and BigDecimal require more memory than simple long or double, and greatly slow down all computations. So if you need extra precision, or your numbers exceed a long range, it's best to think twice. This is probably the only place you need to change in your performance improvement question, especially if you are implementing a mathematical algorithm.

9. First check the current log level

This advice is obvious, but unfortunately, you will find a lot of code that ignores it. Before creating debug messages, you should check the current log level.

Here are two examples of what you shouldn't do.

In both cases, you will perform all the required steps to create log messages without knowing whether the logging framework uses log messages. It is a good idea to check the current log level before creating debug messages.

10. Use Apache Commons StringUtils.Replace instead of String.replace

In general, 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 Apache Commons Lang's StringUtils.replace method. As Lukas Eder described in one of his recent blog posts, it greatly surpasses Java 8's String.replace method.

It only needs minor changes. You just need to add a Maven dependency for Apache's Commons Lang project to your application pom.xml and replace all String.replace method calls with StringUtils.replace method.

11. Cache expensive resources, such as database connections

Caching is a popular solution to avoid re-executing expensive or frequently used pieces of code. The general idea is simple: reusing these resources is much cheaper than creating a new one over and over again.

A typical example is caching database connections in a pool. Creating new connections takes time, which can be avoided if existing connections are reused.

Additional 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 argue that creating a new integer isn't too expensive, but it's used so often that caching the most frequently used values ​​provides a performance benefit.

But when you think about caching, keep in mind that cache implementation also incurs 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 remove stale resources.

Therefore, before you start caching any resource, make sure it is used frequently.


As you can see, improving the performance of an application sometimes doesn't require a lot of work. Most of the advice in this post can actually be applied to code with a little effort.

But usually the most important advice is very programming language agnostic:

* Don't optimize until you know it's necessary
* Use the profiler to find the real bottleneck
* Solve the biggest bottleneck first

Related Articles

Explore More Special Offers

  1. Short Message Service(SMS) & Mail Service

    50,000 email package starts as low as USD 1.99, 120 short messages start at only USD 1.00

phone Contact Us