I am trying to find the best way to address the issue of redundant string concatenation caused by using code of the following form:
logger.debug("Entering loop, arg is: " + arg) // @1
In most cases the logger.level is higher than debug and the arg.toString() and the string concatenation are a waste that user up cpu cycles and briefly use up memory.
Before the introduction of varargs the recommended approach was to test the logger level first:
if (logger.isDebugEnabled())
logger.debug("Entering loop, arg is: " + arg); // @2
But now the preferred form is
logger.debug("Entering loop, arg is: {}", arg); // @3
It is not very difficult to prefix each logger.debug with if (logger.isDebugEnabled()) (and its equivalent for the other methods) in a script, but I am trying to find the best way to convert the first form to the third.
Any suggestions? The challenge is to insert the correct number brace pairs {} in the format string. I wish logback would append the remaining arguments not covered by the placeholder at the end but I cannot find a reference that it does that.
As an alternative, I am thinking to write a class Concatenator as pasted at end and convert the first form to
logger.debug(new Concatenator("Entering loop, arg is: ", arg)); // @4
The Concatenator class delays the call to arg.toString() and string concatenation until the logger calls toString(), thereby avoiding both if the logger is at a higher filter level. It does add the overhead of creating an Object[] and a Concatenator but that should be cheaper than the alternative.
Questions:
- I think this conversion (
@1->@4-- replace+with,and enclose innew Contatenator(...)) is much easier. Is there something I am missing? - Am I correct that
@4is much better than@1?
public class Concatenator {
final Object[] input;
String output;
public Concatenator(Object... input) {
this.input = input;
}
public String toString() {
if (output == null) {
StringBuffer b = new StringBuffer();
for (Object s : input) b.append(s.toString());
output = b.toString();
}
return output;
}
public static void main(String args[]) {
new Concatenator("a", "b", new X());
System.out.println(new Concatenator("c", "d", new X()));
}
}
class X {
public String toString() {
System.out.println("X.toString");
return super.toString();
}
}