How does Log4j 2.x implement lazy argument evaluation?

To avoid argument evaluation, just wrap it in lambda:

logger.debug(() -> { 
   "Entry number: " + i + " is " + String.valueOf(entry[i])
});

In this form, the supplier will be called for construction only before actual logging. Think of it like a function declaration.


I guess what Log4j means, is that with the curly brackets, they avoid constructing a string when its not necessary (e.g. the Level is not Debug):

With

logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));

the complete message is always computed even when it will not be logged.

With

logger.debug("Entry number: {} is {}", i, entry[i]);

Log4j can check the Log-Level first and then decide if its worth to construct the message string. This saves resources needed for string concatenation. It will only call toString() on the objects supplied if the message is actually being created, saving further computation costs.

Log4j uses an internal class (org.apache.logging.log4j.message.ParameterFormatter) that replaces every {} with the arguments provided. It will also catch exceptions thrown by toString() and report these failures.