Java 字符串参数化 - 间接 toString 方法的性能损失

Java String Parameterization - Performace loss on indirect toString methods

我有一个 method 这样的:

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

它是通过日志参数化调用的,如下所示: 我们正在使用 java.util.logging 作为记录器。

logger.log(Level.INFO, "{0}", getOrderListAsString());

问题是,即使记录器级别为 Level.OFF,字符串连接仍在进行。
为了解决这个问题,我们在方法的开头添加了一个 if 语句:

// Declaration:
boolean shouldLog = DebugWriter.getInstance().getLogger().getLevel() != Level.OFF;
// Usage in function:
if(!shouldLog) return null;

但感觉这可以用更聪明的方式来完成。提前致谢!

java.util.logging 具有采用 Supplier<String> 但未与格式字符串组合的重载。所以你可以这样使用它:

logger.info(() -> getOrderListAsString());

或者创建一个具有 toString() 方法的新抽象 OrderList。然后你可以简单地将它作为参数传递,如果需要,记录器将调用 toString()

与 Eran 的回答精神相同,但只是包装参数而不是更改日志实现

public class LazyToString
{
    private final Supplier<String> stringSupplier;

    public LazyToString(Supplier<String> stringSupplier)
    {
        this.stringSupplier = stringSupplier;
    }

    @Override
    public String toString()
    {
        return stringSupplier.get();
    }
}

示例用法:

log.info("Something happened {}", new LazyToString(this::getOrderListAsString));

如果这太冗长,您可以创建一个静态方法调用来创建对象而不是使用 new,也许看起来像这样

log.info("Something happened {}", lazy(this::getOrderListAsString));

如果您使用的是 Java 8+,则 java.util.Logger 具有 log 方法的重载,该方法采用 Supplier

public void log(Level level,
            Supplier<String> msgSupplier)

现在,您可以使供应商生成的字符串类似于

logger.log(Level.INFO, () -> getOrderListAsString());

或者,使用方法参考

logger.log(Level.INFO, this::getOrderListAsString);

Javadoc