Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Built-in string formatting vs string concatenation as logging parameter

I'm using SonarLint that shows me an issue in the following line.

LOGGER.debug("Comparing objects: " + object1 + " and " + object2); 

Side-note: The method that contains this line might get called quite often.

The description for this issue is

"Preconditions" and logging arguments should not require evaluation (squid:S2629)

Passing message arguments that require further evaluation into a Guava com.google.common.base.Preconditions check can result in a performance penalty. That's because whether or not they're needed, each argument must be resolved before the method is actually called.

Similarly, passing concatenated strings into a logging method can also incur a needless performance hit because the concatenation will be performed every time the method is called, whether or not the log level is low enough to show the message.

Instead, you should structure your code to pass static or pre-computed values into Preconditions conditions check and logging calls.

Specifically, the built-in string formatting should be used instead of string concatenation, and if the message is the result of a method call, then Preconditions should be skipped altoghether, and the relevant exception should be conditionally thrown instead.

Noncompliant Code Example

logger.log(Level.DEBUG, "Something went wrong: " + message);  // Noncompliant; string concatenation performed even when log level too high to show DEBUG messages  LOG.error("Unable to open file " + csvPath, e);  // Noncompliant  Preconditions.checkState(a > 0, "Arg must be positive, but got " + a); // Noncompliant. String concatenation performed even when a > 0  Preconditions.checkState(condition, formatMessage());  //Noncompliant. formatMessage() invoked regardless of condition  Preconditions.checkState(condition, "message: %s", formatMessage()); // Noncompliant 

Compliant Solution

logger.log(Level.SEVERE, "Something went wrong: %s", message);  // String formatting only applied if needed  logger.log(Level.SEVERE, () -> "Something went wrong: " + message); //since Java 8, we can use Supplier , which will be evaluated lazily  LOG.error("Unable to open file {}", csvPath, e);  if (LOG.isDebugEnabled() {   LOG.debug("Unable to open file " + csvPath, e);  // this is compliant, because it will not evaluate if log level is above debug. }  Preconditions.checkState(arg > 0, "Arg must be positive, but got %d", a);  // String formatting only applied if needed  if (!condition) {   throw new IllegalStateException(formatMessage()); // formatMessage() only invoked conditionally }  if (!condition) {   throw new IllegalStateException("message: " + formatMessage()); } 

I'm not 100% sure whether i understand this right. So why is this really an issue. Especially the part about the performance hit when using string concatenation. Because I often read that string concatenation is faster than formatting it.

EDIT: Maybe someone can explain me the difference between

LOGGER.debug("Comparing objects: " + object1 + " and " + object2); 

AND

LOGGEr.debug("Comparing objects: {} and {}",object1, object2); 

is in the background. Because I think the String will get created before it is passed to the method. Right? So for me there is no difference. But obviously I'm wrong because SonarLint is complaining about it

like image 527
Naxos84 Avatar asked Feb 22 '17 10:02

Naxos84


People also ask

Is string format faster than concatenation Java?

Therefore, concatenation is much faster than String.

What are the benefits of using the .format method instead of string concatenation?

The main advantages of using format(…) are that the string can be a bit easier to produce and read as in particular in the second example, and that we don't have to explicitly convert all non-string variables to strings with str(…).

What are the 2 methods used for string concatenation?

There are two ways to concatenate strings in Java: By + (String concatenation) operator. By concat() method.

Which is faster string concatenation or the StringBuilder class?

Note that regular string concatenations are faster than using the StringBuilder but only when you're using a few of them at a time. If you are using two or three string concatenations, use a string.


1 Answers

I believe you have your answer there.

Concatenation is calculated beforehand the condition check. So if you call your logging framework 10K times conditionally and all of them evaluates to false, you will be concatenating 10K times with no reason.

Also check this topic. And check Icaro's answer's comments.

Take a look to StringBuilder too.

like image 149
luso Avatar answered Oct 04 '22 10:10

luso