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
@4
is 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();
}
}