Java Performance Tuning Tips For Programmers

Java Performance Tuning Tips For Programmers 2018. Want to make your project always high-performance operation? Here Coding compiler sharing some tips you can take to eliminate cache bottlenecks, as well as some other performance tuning suggestions. All the best and happy learning.

Java Performance Tuning

Most developers think that performance optimization is a complex topic that requires a lot of work experience and related knowledge theory. Well, this is not completely wrong. Optimizing an application for performance optimization may not be an easy task, but that does not mean you can not do anything without knowledge.

Java Performance Tuning Tips

Here are some easy to follow recommendations and best practices to help you create a good application.

  1. Do not rush to optimize until you clearly need it
  2. Use the analyzer to find the real bottleneck
  3. Create a performance test suite for the entire application
  4. Give priority to the biggest bottleneck
  5. Use StringBuilder to programmatically concatenate strings
  6. Use + to concatenate a string in a statement
  7. Use basic types whenever possible
  8. Try to avoid large integers and decimals
  9. Priority check the current log level
  10. Use Apache Commons StringUtils.Replace instead of String.replace
  11. Expensive cache resources, such as database connections

Most of these suggestions are for the Java language. But there are some languages that are not language-specific and you can apply them to any application or program. Before we learn about Java programming performance tuning, let’s explore some common techniques.

1) Do not rush to optimize until you clearly need it

This is probably one of the most important performance tuning tips. You should follow common best practices and apply it effectively in your case. However, this does not mean that you should replace any standard library or build complex optimizations until proven necessary.

In most cases, premature optimization can take a long time and can make the code harder to read and read. To make matters worse, these optimizations do not usually make any difference because you spend a lot of time optimizing non-critical parts of your application.

So, how to prove that things need to be optimized?

First, you need to define your code much faster. For example, specify the maximum response time for all API calls, or specify the number of records to import within a specific time range. After doing this, you need to determine which parts of your application are too slow to improve. When done, you can take a look at the second tip.

2) Use the analyzer to find the real bottleneck

After completing the first part of the optimization recommendations to identify your application need to enhance the part, where to start from?

There are two ways you can solve this problem:

  1. Check your code, starting with something that looks suspicious or where you think it might cause problems.
  2. Or use the analyzer to get the behavior of each part of the code (execution process) and performance details.

I hope I do not need to explain why you should always follow the second approach / method.

Obviously, the parser-based approach allows you to better understand the performance impact of code and allows you to focus on the more critical part (code). Even if you’ve used parsers before, you’ll have to remember how surprised you were to find out which parts of your code are causing performance problems. My first guess led me more than once in the wrong direction.

3) Create a performance test suite for the entire application

This is another general-purpose trick that can help you avoid many of the unexpected issues that often occur after deploying performance improvements into your product. You should always define a performance test suite to test the entire application and run it before and after performance improvements.

These extra tests will help you identify the functional and performance side effects of your changes and ensure they do not lead to more harm than good updates. This is especially important if you are dealing with components that are used by different parts of the application, such as databases or caches.

4) Give priority to the biggest bottleneck

After you have created a test suite and analyzed your application with a profiler, you can list a list of issues that need to be addressed to improve performance. This is fine, but it does not answer the question of where you need to start. You can focus on quick fixes or start with the most important questions.

The quick start may be appealing at the beginning because you can quickly show the first result. But sometimes, it may be necessary to convince other team members or management that performance analysis is worth it.

In general, I suggest starting with the top-level, first to start with the most important performance issues. This will provide you with the maximum performance improvement, and you may only need to address a few of these problems to meet your performance requirements.

This is the end of common tuning techniques. Let’s take a closer look at some Java-specific skills.

5) Use StringBuilder to programmatically concatenate strings

There are many different options in Java to concatenate strings. For example, you could use simple + or + = as well as old StringBuffer or StringBuilder.

So, what method should you choose?

The answer depends on the code that concatenates the string. If you programmatically add new content to a string, such as in a for loop, you should use StringBuilder. It’s easy to use and offers better performance than StringBuffer. However, keep in mind that StringBuilder is not thread-safe compared to StringBuffer and may not be suitable for all situations.

You only 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 connected 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  along with spaces  . So, finally, this code writes “This is a test0 1 2 3 4 5 6 7 8 9” in 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. We can provide the first element of the string into the constructor. This will create a  StringBuilder  that contains the string you provide and the capacity of 16 additional characters. When you add more characters to  StringBuilder  , your JVM will dynamically increase  the size of the StringBuilder  .

If you already know how many characters the string will contain, you can supply that number to a different constructor to instantiate a StringBuilder with the specified size. This further increases efficiency because it does not need to dynamically scale its capacity.

6) Use + to concatenate a string in a statement

When you use Java to implement your first application, someone may have told you not to use + to connect strings. This is true if you are concatenating strings within your application logic. Strings are immutable, and the concatenation of each string is stored in a new string object. This requires extra storage and may slow 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, this does not apply if you simply improve the readability of the code by breaking the string into multiple lines.

Query q = em.createQuery ("SELECT a.id, a.firstName, a.lastName"
+ "FROM Author a"
+ "WHERE a.id =: id");

In these scenarios, you should use simple + to concatenate strings. Your Java compiler optimizes it and completes the connection at compile time. Therefore, your code will only use one string at runtime, and does not require any linking operations.

7) Use basic types whenever possible

Another quick and easy way to avoid any overhead and improve application performance is to use base types instead of their wrapper classes. So, it’s best to use int instead of Integer, double instead of Double. This will allow your  JVM  to store the value on the stack instead of the heap to reduce memory consumption and handle it more efficiently.

8) Try to avoid large integers and decimals

Since we are already talking about data types, we should also be able to quickly browse for large integers and decimals. In particular, the latter is popular for its accuracy. But this is a price.

Larger integers and decimals  require more memory than a simple  long  or  double type and can significantly slow down all operations. So, if you need extra precision, or if your numbers go beyond a longer range, it’s best to think twice. This may be the only way you need to change and solve performance problems, especially when implementing mathematical algorithms.

9) Priority check the current log level

This advice should be obvious, but unfortunately, many people ignore it when writing code. Before creating a debug message, you should always prioritize the current log level. Otherwise, you might create a string that appends your log message, and the string is ignored after that.

Here are two negative examples that you should not do.

// do not do this
log.debug ("User [" + userName + "] called method X with [" + i + "]");
// or this
log.debug (String.format ("User [% s] called method X with [% d]", userName, i));

In both of these examples, you will perform all the necessary steps to create a log message without knowing if the log framework will use log messages. Therefore, before creating debug messages, it is best to check the current log level.

// do thisif (log.isDebugEnabled ()) {
    log.debug ("User [" + userName + "] called method X with [" + i + "]");
}

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

In general, the String.replace method works fine and is very efficient, especially if you are using Java 9. However, if your application requires a large number of replacements and does not update to the latest Java version, it may still be necessary to examine faster and more efficient alternatives.

One alternative is  the  StringUtils.replace method of  Apache Commons Lang . It outperforms Java 8’s String.replace method. 

And it requires only minor changes. You simply add the Maven dependencies for the Apache Commons Lang project to your application’s pom.xml and replace all calls to String.replacemethod with the StringUtils.replace method.

// replace this
test.replace ("test", "simple test");
// with this
StringUtils.replace (test, "test", "simple test");

11) expensive cache resources, such as database connections

Caching is a popular solution to avoid repeatedly executing expensive or commonly used code snippets. The general idea is simple: reusing these resources is more cost-effective than creating a new one.

A typical example is the database connection in the cache pool. The creation of a new connection takes time, and you can avoid it if you reuse existing connections.

You can find other examples in the Java language source. For example, the valueOf method in the Integer class caches values between -128 and 127. You might argue that creating a new Integer is not too expensive, but since it is often used, the most common value for caching can also provide performance benefits.

However, when you consider caching, keep in mind that the cache implementation also incurs overhead. You need to spend extra memory to store reusable resources, so you may need to manage your cache to make the resources accessible and remove outdated resources.

So, before you start caching any resource, make sure that they are often used to exceed the cost of the cache implementation.

Related Articles

Aricent Java Interview Questions

Accenture Java Interview Questions

Core Java Interview Questions

Advanced Java Interview Questions

What is Python?

Advantages of Python

Python Tutorial For Beginners

295 Android Interview Questions

Leave a Comment