问题
I've got a method like this:
private String getOrderListAsString() {
StringBuilder str = new StringBuilder();
str.append("Sell list:");
for (Order o : sellOrderList) {
str.append("\nSale: ").append(o);
}
str.append("Buy list:");
for (Order o : buyOrderList) {
str.append("\nBuy: ").append(o);
}
return str.toString();
}
It's called with logging parameterization like so: We're using java.util.logging as a logger.
logger.log(Level.INFO, "{0}", getOrderListAsString());
The problem is that the string concatination is still being done even if the logger level is Level.OFF.
To get around this we've added an if statement at the start of the method:
// Declaration:
boolean shouldLog = DebugWriter.getInstance().getLogger().getLevel() != Level.OFF;
// Usage in function:
if(!shouldLog) return null;
But it feels like this could be done in a more clever way. Thanks in advance!
回答1:
If you are using Java 8+, then java.util.Logger has an overload of the log method that takes a Supplier
public void log(Level level,
Supplier<String> msgSupplier)
Now, you can make the string generated from a supplier like
logger.log(Level.INFO, () -> getOrderListAsString());
or, using method reference
logger.log(Level.INFO, this::getOrderListAsString);
Javadoc
回答2:
java.util.logging has overloads that take Supplier<String> but not in combination with a format string. So you can use it like this:
logger.info(() -> getOrderListAsString());
Or create a new abstraction OrderList that has a toString() method. Then you can simply pass it as a parameter, and the logger will invoke toString(), if needed.
回答3:
Same spirit as Eran's answer, but just wrap the argument rather than change the log implementation
public class LazyToString
{
private final Supplier<String> stringSupplier;
public LazyToString(Supplier<String> stringSupplier)
{
this.stringSupplier = stringSupplier;
}
@Override
public String toString()
{
return stringSupplier.get();
}
}
Sample usage:
log.info("Something happened {}", new LazyToString(this::getOrderListAsString));
If that's too verbose, you can create a static method call which creates the object rather than using new, maybe would look something like this
log.info("Something happened {}", lazy(this::getOrderListAsString));
来源:https://stackoverflow.com/questions/59284520/java-string-parameterization-performace-loss-on-indirect-tostring-methods