Home > Software design >  How do I log non-final variables using a lazily evaluated expression?
How do I log non-final variables using a lazily evaluated expression?

Time:12-30

I would like to create a log message which contains the values of at least one local variable. To benefit form lazy evaluation I would like to pass a Supplier<String> to the logging frame work.

private void  doSomething(Object a, Object b){
   var myLocalVar = deriveValFrom(a);
   if (null == myLocalVar){
       myLocalVar = deriveValFrom(b);
   }
   LOG.debug(() -> String.format("settled on value %s", myLocalVar));
}

The code above does not compile, since myLocalVar is neither final nor effectively final.

current ideas As the answers to this question show, I might define a temp variable and thus bloat the code.

Otherwise I could implement a private method like

private void logToDebug(String formatStr, Object p0, Objects... objs){
   LOG.debug(()->String.format(formatStr, p0, objs));
}

Which makes the compiler stop complaining but adds 'off-topic' code to the class.

actual Q Is there a better way to achieve lazy evaluation and concise code?

relevant info While logging is done under the hood by log4j I have to work through a custom facade which I may extend (for instance with the debug(String formatStr, p0, ...)-Methods) but I would like to keep the extension to a minimum.

CodePudding user response:

I'd split logic into two methods:

private void doSomething(Object a, Object b){
    final var myLocalVar = deriveValFrom(a);
    if (myLocalVar != null)
        return myLocalVar;
    return deriveValFrom(b);
}

private void doSomethingAndLog(Object a, Object b){
    final var myLocalVar = doSomething(a, b);
    LOG.debug(() -> String.format("settled on value %s", myLocalVar));
}

CodePudding user response:

It depends a bit on what part of the exection you want to be lazy. A final constant would normally use an assignless expression. Optional is very suitable for that.

But you can do all in the log call.

private void  doSomething(Object a, Object b) {
   final var myLocalVar = Optional.ofNullable(deriveValFrom(a))
                                  .orElseGet(() -> deriveValFrom(b)));
   LOG.debug(() -> "settled on value %s".formatted(
       Optional.ofNullable(deriveValFrom(a))
               .orElseGet(() -> deriveValFrom(b)));
}
  • Related