在博客文章“在Log4j2中更好地执行非日志记录器调用”中 ,我介绍了可以在Log4j 2中使用的方法,这些方法可以减少或避免在基于指定日志级别实际上根本未记录的日志语句中调用方法。 作为讨论的一部分,我介绍了Log4j 2对使用lambda表达式的基于Java 8的延迟执行的支持。 在本文中,我将演示如何使用内置的java.util.logging ( JUL )支持来使用lambda表达式延迟执行日志语句中的方法,其方式类似于Log4j 2所支持的方式。
java.util.logging.Logger类级别的Javadoc文档描述了JUL对延迟执行的支持:
一组方法也可以使用“ msgSupplier”而不是“ msg”参数。 这些方法需要供应商
该函数仅在基于有效日志级别实际记录消息时才调用以构造所需的日志消息,从而消除了不必要的消息构造。
浏览java.util.logging.Logger
的公共API,可以快速浏览该注释中引用的方法,该方法使用供应商来允许推迟方法调用,直到真正知道需要进行日志为止。 接受内置功能接口 java.util.function.Supplier的实例作为参数的code.util.logging.Logger
方法。 例如,下一个屏幕快照使用一些接受Supplier
的方法来捕获HTML呈现的Javadoc的一小部分。
我喜欢使用javap轻松查看Java类的公共API。 在这种情况下,可以通过执行$JAVA_HOME/jre/lib
目录javap -classpath rt.jar java.util.logging.Logger
的命令javap -classpath rt.jar java.util.logging.Logger
来完成此操作(假设已配置了JAVA_HOME
环境变量)。 下一个屏幕快照描述了该命令的执行以及结果的第一部分。 屏幕快照之后是输出的文本版本, 强调了Supplier
的使用。
Compiled from "Logger.java"
public class java.util.logging.Logger {static final java.lang.String SYSTEM_LOGGER_RB_NAME;public static final java.lang.String GLOBAL_LOGGER_NAME;public static final java.util.logging.Logger global;static final boolean $assertionsDisabled;public static final java.util.logging.Logger getGlobal();protected java.util.logging.Logger(java.lang.String, java.lang.String);java.util.logging.Logger(java.lang.String, java.lang.String, java.lang.Class<?>, java.util.logging.LogManager, boolean);void setLogManager(java.util.logging.LogManager);public static java.util.logging.Logger getLogger(java.lang.String);public static java.util.logging.Logger getLogger(java.lang.String, java.lang.String);static java.util.logging.Logger getPlatformLogger(java.lang.String);public static java.util.logging.Logger getAnonymousLogger();public static java.util.logging.Logger getAnonymousLogger(java.lang.String);public java.util.ResourceBundle getResourceBundle();public java.lang.String getResourceBundleName();public void setFilter(java.util.logging.Filter) throws java.lang.SecurityException;public java.util.logging.Filter getFilter();public void log(java.util.logging.LogRecord);public void log(java.util.logging.Level, java.lang.String);public void log(java.util.logging.Level, java.util.function.Supplier<java.lang.String>);public void log(java.util.logging.Level, java.lang.String, java.lang.Object);public void log(java.util.logging.Level, java.lang.String, java.lang.Object[]);public void log(java.util.logging.Level, java.lang.String, java.lang.Throwable);public void log(java.util.logging.Level, java.lang.Throwable, java.util.function.Supplier<java.lang.String>);public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String);public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.util.function.Supplier<java.lang.String>);public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.Object);public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[]);public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable);public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.Throwable, java.util.function.Supplier<java.lang.String>);public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String);public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object);public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[]);public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.util.ResourceBundle, java.lang.String, java.lang.Object...);public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable);public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.util.ResourceBundle, java.lang.String, java.lang.Throwable);public void entering(java.lang.String, java.lang.String);public void entering(java.lang.String, java.lang.String, java.lang.Object);public void entering(java.lang.String, java.lang.String, java.lang.Object[]);public void exiting(java.lang.String, java.lang.String);public void exiting(java.lang.String, java.lang.String, java.lang.Object);public void throwing(java.lang.String, java.lang.String, java.lang.Throwable);public void severe(java.lang.String);public void warning(java.lang.String);public void info(java.lang.String);public void config(java.lang.String);public void fine(java.lang.String);public void finer(java.lang.String);public void finest(java.lang.String);public void severe(java.util.function.Supplier<java.lang.String>);public void warning(java.util.function.Supplier<java.lang.String>);public void info(java.util.function.Supplier<java.lang.String>);public void config(java.util.function.Supplier<java.lang.String>);public void fine(java.util.function.Supplier<java.lang.String>);public void finer(java.util.function.Supplier<java.lang.String>);public void finest(java.util.function.Supplier<java.lang.String>);public void setLevel(java.util.logging.Level) throws java.lang.SecurityException;final boolean isLevelInitialized();public java.util.logging.Level getLevel();public boolean isLoggable(java.util.logging.Level);public java.lang.String getName();public void addHandler(java.util.logging.Handler) throws java.lang.SecurityException;public void removeHandler(java.util.logging.Handler) throws java.lang.SecurityException;public java.util.logging.Handler[] getHandlers();java.util.logging.Handler[] accessCheckedHandlers();public void setUseParentHandlers(boolean);public boolean getUseParentHandlers();public void setResourceBundle(java.util.ResourceBundle);public java.util.logging.Logger getParent();public void setParent(java.util.logging.Logger);final void removeChildLogger(java.util.logging.LogManager$LoggerWeakRef);static java.util.logging.Logger$LoggerBundle access$000();static java.util.logging.Logger$LoggerBundle access$100();static {};
}
从java.util.logging.Logger
的公共API可以看出,有很多重载的方法用于“精确日志记录”(接受显式指定的类和方法名称的两个String
的logp
方法)以及用于接受实例的“常规日志记录” Supplier
。 这些方法仅在将日志记录级别设置为足以写入日志语句的特定级别时,才可以处理供应商。
以下是接受Supplier
实例的当前java.util.logging.Logger
方法的列表:
- 常规的特定级别的日志记录方法
public void severe (java.util.function.Supplier<java.lang.String>);
- 需要规范日志级别的常规常规日志记录方法
public void log (java.util.logging.Level, java.util.function.Supplier<java.lang.String>);
- “精确”的记录方法
public void logp (java.util.logging.Level, java.lang.String, java.lang.String, java.util.function.Supplier<java.lang.String>);
请记住,精确的日志记录方法(名称为logp
)接受其类和方法名称的String
参数,可以观察到JUL的延迟调用日志记录API与Log4j 2的实现之间的最大区别之一:JUL的实现不允许“消息”字符串,作为其日志记录方法的单独(附加)参数提供。
在我以前的博客文章中 ,我演示了Log4j 2的org.apache.logging.log4j.Logger.debug(String message,Supplier <?> ... paramSuppliers)方法的使用,该方法除了延迟执行提供的Supplier
之外还接受消息String
。 。 Log4j 2的org.apache.logging.log4j.Logger
提供了类似的方法来处理其他特定的日志级别( 错误 , 致命 , 信息 , 跟踪和警告 )以及具有明确级别的日志级别的常规日志记录。 通过与Supplier
分开的String
轻松提供上下文的额外灵活性是一个不错的选择。 还值得注意的是, Log4j 2的Logger
还支持类似于java.util.logging.Logger
提供的方法的各种日志方法,这些方法仅接受Supplier
(没有任何上下文消息String
)。
John Shepard在博客文章尝试Java 8的五大理由中写道:“现在可以从方法, log.isLogLevelEnabled
和类似的方法中传递函数(并返回)了,不再需要在代码库中log.isLogLevelEnabled
。” 然后,他提供了一个简单的代码清单,演示了当消息上下文的单个String
参数不属于方法签名的情况时,如何通过此API提供String
上下文。 我在本文结尾处的示例将与此类似。
正如我在“在Log4j2中更好地执行非日志记录器调用”一文中所讨论的那样 ,由Java lambda表达式提供支持的延迟执行允许开发人员通过将传入对象的隐式和显式方法调用都推迟到lambda表达式被执行之前,从代码中删除日志保护。解决。 如果运行软件的日志记录级别的特定性低于消息的特定日志级别,则永远不会执行此操作。 换句话说,可以从下一个显示的代码清单转换代码,就像其后的较小代码清单一样。
if (logger.isLoggable(Level.FINE))
{logger.fine("GUARDED: " + slow);
}
if (logger.isLoggable(Level.FINE))
{logger.fine(expensiveOperation());
}
logger.fine(() -> "LAMBDA: " + slow);
logger.fine(this::expensiveOperation);
尽管软件开发中的许多事情实际上都是品味和见解的问题,但很难想象有很多理由支持较早的,更冗长的代码。 尽管有一些断言,但是更少的代码并不总是对每个人都可读。 但是,在这种情况下,我相信很少有开发人员会争辩说,更冗长的代码无论如何都比Java 8版本更好。
翻译自: https://www.javacodegeeks.com/2016/04/java-8-deferred-invocation-java-util-logging.html