问题描述
我经常听到人们说这是避免String Concatenation并在记录时使用{}的最佳实践之一.
我正在研究Log4j代码,以查看他们如何处理此操作,并认为他们正在做类似的事情.
这是format()方法的片段,它采用模式和参数并返回要记录的消息.
/** * Formats arguments using SLF4J-like formatter. * @param pattern pattern, may be malformed. * @param arguments arguments. * @return Message string */ private static String format(final String pattern, final Object[] arguments) { if (pattern != null) { String retval = ""; int count = 0; int prev = 0; int pos = pattern.indexOf("{"); while(pos >= 0) { if (pos == 0 || pattern.charAt(pos-1) != '\\') { retval += pattern.substring(prev, pos); if (pos + 1 < pattern.length() && pattern.charAt(pos+1) == '}') { if(arguments != null && count < arguments.length) { retval += arguments[count++]; } else { retval += "{}"; } prev = pos + 2; } else { retval += "{"; prev = pos + 1; } } else { retval += pattern.substring(prev, pos - 1) + "{"; prev = pos + 1; } pos = pattern.indexOf("{", prev); } return retval + pattern.substring(prev); } return null; }
我无法理解该实现比使用串联更好.对此的任何见解都会有所帮助.
推荐答案
格式字符串在记录系统中的好处是,记录系统可以决定是否必须发生字符串串联.
让我们以这些行为例:
log.debug("Count: " + list.size()); log.debug("Count: {}", list.size());
只要此记录器的级别是调试或以下,性能就没有差异,但是如果日志级别高于调试,则第二行不会执行串联.
其他推荐答案
这个问题的一些答案解释:
简短版本是基于格式的用法更快,因为在
中Logger.debug("my name is {}", name);
昂贵的字符串仅发生 log4j决定需要记录该事件;例如根据日志记录级别进行过滤之后,等等.
相比之下,带有字符串串联版本
Logger.debug("my name is " + name);
在评估参数时,弦扑打会发生.因此,即使在没有事件实际记录的情况下,也会发生.您可以通过在代码中添加"守卫"来部分避免这种情况(请参见下文),但是这样做会使您的应用程序记录呼叫冗长.
但要看一下这个示例:
log.debug("Count: " + list.size()); log.debug("Count: {}", list.size());
格式版本将更快,但是两个版本始终评估list.size()表达式.如果这是一个昂贵的操作,那么您可能需要求助于使用警卫.例如
if (log.isDebugEnabled()) { log.debug("Count: " + list.size()); }
其他推荐答案
替代替代执行list.size():
// Instead of if (log.isDebugEnabled()) { log.debug("Count: " + list.size()); } // Use if >= Java 8 log.debug("Count: {}", () -> list.size());
这仅在需要时评估list.size().
信用: https://garygregory.wordpress.com/2015/09/16/a-gentle-introduction-to-the-the-the-the-log4j-ap-ap-api-and-and-lambda-basics/
问题描述
I have often heard people saying that its one of the best practices to avoid String Concatenation and use {} instead while logging.
I was looking into the Log4j code to see how they have handled this and figured that they are doing something similar.
Here is a snippet of format() method which takes the pattern and arguments and returns the message to be logged.
/** * Formats arguments using SLF4J-like formatter. * @param pattern pattern, may be malformed. * @param arguments arguments. * @return Message string */ private static String format(final String pattern, final Object[] arguments) { if (pattern != null) { String retval = ""; int count = 0; int prev = 0; int pos = pattern.indexOf("{"); while(pos >= 0) { if (pos == 0 || pattern.charAt(pos-1) != '\\') { retval += pattern.substring(prev, pos); if (pos + 1 < pattern.length() && pattern.charAt(pos+1) == '}') { if(arguments != null && count < arguments.length) { retval += arguments[count++]; } else { retval += "{}"; } prev = pos + 2; } else { retval += "{"; prev = pos + 1; } } else { retval += pattern.substring(prev, pos - 1) + "{"; prev = pos + 1; } pos = pattern.indexOf("{", prev); } return retval + pattern.substring(prev); } return null; }
I'm not able to understand how this implementation is better than using concatenation. Any insights into this will be really helpful.
推荐答案
The benefit of format strings in logging systems is, that the logging system can decide if the string concatenation must happen or not.
Let's use these lines as example:
log.debug("Count: " + list.size()); log.debug("Count: {}", list.size());
As long as the level for this logger is debug or below, there is no difference in performance, but if the log level is higher than debug the second line won't perform the concatenation at all.
其他推荐答案
Some of the answers to this question explain:
The short version is that format-based usage faster because in
Logger.debug("my name is {}", name);
the expensive string bashing only occurs after log4j decides that the event needs to be logged; e.g. after the filtering based on the logging level, etcetera.
By contrast, with the string concatenation version
Logger.debug("my name is " + name);
the string bashing happens while evaluating the arguments. Thus, it happens even in the cases where no event is actually logged. You can partially avoid that by adding "guards" in your code (see below), but doing that makes your applications logging calls verbose.
But take a look at this example:
log.debug("Count: " + list.size()); log.debug("Count: {}", list.size());
The format version will be faster, but both versions always evaluate the list.size() expression. If that is an expensive operation, then you may need to resort to using a guard; e.g.
if (log.isDebugEnabled()) { log.debug("Count: " + list.size()); }
其他推荐答案
Alternative to not execute list.size() :
// Instead of if (log.isDebugEnabled()) { log.debug("Count: " + list.size()); } // Use if >= Java 8 log.debug("Count: {}", () -> list.size());
This will evaluate list.size() only when needed.