【问题标题】:Java String Parameterization - Performace loss on indirect toString methodsJava 字符串参数化 - 间接 toString 方法的性能损失
【发布时间】:2020-04-04 15:51:00
【问题描述】:

我有一个这样的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;

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

【问题讨论】:

  • 整个项目都在我的掌控之中。理论上我可以改变任何东西
  • 按照您编写代码的方式,方法getOrderListAsString()总是被调用,无论日志级别如何。您需要在生成日志消息之前检查日志级别。

标签: java performance string-concatenation


【解决方案1】:

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

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

现在,您可以制作从供应商生成的字符串,例如

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

或者,使用方法参考

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

Javadoc

【讨论】:

  • 唯一的缺点是我不能使用 "{0}" 符号
【解决方案2】:

与 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));

【讨论】:

  • 看起来很不错。我一定会保存的!现在我将使用@user7 的答案,因为它更小,我不需要{} 解析。但是当我这样做时,我可能不得不切换到这个。感谢您回答所有问题,以及之前的问题!
【解决方案3】:

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

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

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

【讨论】:

    猜你喜欢
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    • 2011-11-08
    • 2013-03-29
    • 2014-09-11
    • 2018-02-07
    • 2010-12-04
    相关资源
    最近更新 更多