如何使方法参数评估延迟?

huangapple go评论39阅读模式
英文:

How to make method argument evaluation lazy?

问题

我在我的代码中有一个调试日志语句,我正在将一个昂贵方法调用的结果传递给它。

log.debug("数据 - {}", obj.costlyMethodCall());


现在,即使调试日志被禁用,**obj.costlyMethodCall()** 仍然会被评估并作为方法参数传递。

一种减轻这个问题的方法是明确检查调试日志是否启用

if (log.isDebugEnabled()) {
log.debug("数据 - {}", obj.costlyMethodCall());
}

但这降低了代码的可读性。

是否有更好的方法使 **obj.costlyMethodCall()** 的调用变得懒惰或有条件地执行?
英文:

I have a debug log statement in my code to which I am passing a result of costly method call.

log.debug("Data - {}", obj.costlyMethodCall());

Now, even if debug logging is disabled, obj.costlyMethodCall() will always be evaluated to be passed as method argument.

One way to mitigate this is to have a explicit check if debug logging is enabled

if (log.isDebugEnabled()) {
  log.debug("Data - {}", obj.costlyMethodCall());
}

But this reduces code readability.

Is there any better way to make invocation of obj.costlyMethodCall() lazy or conditional here?

答案1

得分: 5

通常,可以通过使用接受类似于Supplier而不是具体Object的方法来解决这个问题,以便您可以传入类似于以下的内容:

log.debug("Data - {}", () -> obj.costlyMethodCall());

其中log.debug类似于以下内容:

public void debug(String message, Supplier<Object> supplier) {
    Object value = supplier.get(); // costlyMethodCall 仅在此处调用
    // ...
}
英文:

Usually this is solved by having a method accepting something similar to a Supplier instead of a concrete Object so that you can pass in something like

log.debug(&quot;Data - {}&quot;, () -&gt; obj.costlyMethodCall());

where log.debug is something like

public void debug(String message, Supplier&lt;Object&gt; supplier) {
    Object value = supplier.get(); // costlyMethodCall is only called here
    // ...
}

答案2

得分: 3

是的,你可以使用lambda表达式来延迟执行。新版本的日志记录器采用了这种方法,例如log4j 2.4。如果可能的话,你不需要提供新的方法,只需使用更新的日志记录API。

你可以这样做:

log.debug("Data - {}", () -> obj.costlyMethodCall());

他们在最近的日志记录器中添加了这个功能,可以延迟字符串的使用,而不会污染你的代码,不需要if(log.isDebugEnabled())...

你传递了一个Supplier,它将在被调用时返回字符串。

如果需要的话,你可以查看这个链接:https://garygregory.wordpress.com/2015/09/16/a-gentle-introduction-to-the-log4j-api-and-lambda-basics/

英文:

Yes, you could use lamdba expression to delay that. New versions of logger use this approach, like log4j 2.4. You don't need to provide new methods, just use newer logging API if you can.

You can do the following:

log.debug(&quot;Data - {}&quot;, () -&gt; obj.costlyMethodCall());

They added this in recent logger where you need to delay String usage, without polluting your code with the if(log.isDebugEnabled())...

You pass a Supplier that will return the Strings, only once called.

You can check this link if you need to: https://garygregory.wordpress.com/2015/09/16/a-gentle-introduction-to-the-log4j-api-and-lambda-basics/

答案3

得分: 2

如果您已经广泛采用了一个日志框架,按照Smutje的建议定义自己的方法可能不是一个实际的选项。

相反,可以定义一个静态方法,类似于:

static <T> Supplier<T> lazy(Supplier<? extends T> delegate) {
  return new Supplier<T>() {
    @Override public T get() { return delegate.get(); }
    @Override public String toString() { return Objects.toString(get()); }
  };
}

然后将其作为参数提供给您的调用:

log.debug("Data - {}", lazy(() -> obj.costlyMethodCall()));

如果您没有提供一个覆盖toString()Supplier,日志库可能无法(必要时)知道需要评估供应商以构建toString()Ideone示例

英文:

If you are already extensively bought into a logging framework, defining your own methods, as suggested by Smutje, may not be a practical option.

Instead, define a static method something like:

static &lt;T&gt; Supplier&lt;T&gt; lazy(Supplier&lt;? extends T&gt; delegate) {
  return new Supplier&lt;T&gt;() {
    @Override public T get() { return delegate.get(); }
    @Override public String toString() { return Objects.toString(get()); }
  };
}

Then provide this as an argument to your call:

log.debug(&quot;Data - {}&quot;, lazy(() -&gt; obj.costlyMethodCall()));

If you don't provide a Supplier which overrides toString(), the logging library can't (necessarily) know that it needs to evaluate the supplier to build the toString(). Ideone example.

huangapple
  • 本文由 发表于 2020年7月30日 15:52:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/63168584.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定