kotlin 和java_Java 8和Kotlin中的智能日志记录

本文探讨了Java和Kotlin中智能日志记录的挑战和解决方案。在Java中,由于字符串串联的性能成本,以及SLF4J在日志未写入时仍会评估变量,导致了一些问题。Java 8引入了 Supplier 接口来优化这种情况。而在Kotlin中,利用扩展函数可以提供更优雅的解决方案,使日志调用更高效且可读性强。文章还提到了Log4J 2已内置类似功能,并提供了自定义SLF4J包装器的源代码和依赖信息。
摘要由CSDN通过智能技术生成

kotlin 和java

伐木不是一个性感的话题,但仍然很重要。 在Java世界中,日志记录框架通过Commons Logging和JDK日志记录(从Log4JSLF4J)不等(暂时不包括Log4J 2)。 尽管其架构和功能有所不同,但它们的所有API看起来都是相同的。 记录器针对每个日志级别都有一个方法, 例如

  • debug(String message)
  • info(String message)
  • error(String message)
  • 等等

级别组织成层次结构。 一旦在某个级别上配置了框架,将仅写入以相同或更高优先级记录的消息。

到目前为止,一切都很好。 当消息包含变量以便必须将它们串联时,就会出现问题。

LOGGER.debug("Customer + "customer.getId()+" has just ordered "+item.getName()+" ("+item.getId()+")");

在Java中,字符串串联具有一定的性能成本, 无论配置的日志级别如何,都会发生。

因此,诸如SLF4J之类的现代日志记录框架提供了改进的签名,可以接受类型为String的消息格式和变量为Object varargs的消息格式。 在这种情况下,仅当记录器有效写入时才发生串联。

LOGGER.debug("Customer {} has just ordered {} ({})",customer.getId(),item.getName(),item.getId());

但是,有时变量不容易获得,而必须仅出于记录的目的而明确地进行计算。

LOGGER.debug("Customer {} has just ordered {}",customer.getId(),order.expensiveComputation());

SLF4J对此无济于事,因为即使记录器决定不写,因为框架配置了更高的优先级,该方法也会被评估。 因此,在这种情况下,建议将logger方法调用包装在相关的优先级检查中。

if(LOGGER.isDebug()){
    LOGGER.debug("Customer {} has just ordered {}",customer.getId(),order.expensiveComputation());
}

必须对每个昂贵的方法调用进行此操作,因此它需要严格的编码规则并进行检查,以确保在相关时才进行换行,但仅在那时才进行。 此外,它降低了可读性,从而降低了可维护性。 为了在没有这些缺点的情况下自动实现相同的结果,可以使用AOP ,但要付出额外的复杂性。

带有Java 8和Supplier<T>接口,该接口返回String ,因此可以这样创建方法:

publicvoiddebug(Supplier<String>s){
   if(LOGGER.isDebugEnabled()){
        LOGGER.debug(s.get());
   }
}

在那种情况下, 当包装条件的值为true时, 调用get()方法。

使用此方法非常简单:

debug(()->("Customer + "customer.getId()+" has just ordered "+order.expensiveComputation());

大! 但是,将改进的debug()方法放在哪里?

  • 在课程本身中:每个课程重复一次。 真?
  • 在实用程序类中:应该将LOGGER添加为第一个参数。 你说烦吗
  • 在记录器中:可以创建包装器并将标准记录器保留为委托,但是工厂是final (至少在SLF4J中如此),并且具有许多private方法。
  • 一方面:回到正方...

这是在Java领域开始情况不太理想的步骤。

那Kotlin呢? 它带有扩展功能 (和属性)。 这可能是以后发布的主题,因为您仅应将此功能用于Kotlin。 足以说Kotlin可以使其看起来像可以为已经定义的类型添加状态和行为。

因此,可以在一个适当命名的文件中定义debug()

funLogger.debug(s:()->String){
    if(isDebugEnabled)debug(s.invoke())
}

调用它真的感觉就像调用标准记录器,只传递了一个lambda:

LOGGER.debug{"Customer + "customer.getId()+" has just ordered "+order.expensiveComputation()}

最后,让我们内联定义的函数。 这样,编译器将有效地用bytecode中的方法替换调用该方法的每个位置。 我们获得了可读语法的好处,并避免了在运行时解开lambda的开销:

inlinefunLogger.debug(s:()->String){
    if(isDebugEnabled)debug(s.invoke())
}

请注意,尽管语法不太好,但仍可以在Java中调用它:

Slf4KUtilsKt.debug(LOGGER,()->"Customer + "+customer.getId()+" has just ordered "+order.expensiveComputation());

还要注意,Log4J 2已经开箱即用地实现了此功能

至此,在需要时将上述代码段复制编码就足够简单了。 但是开发人员本质上是懒惰的 ,所以我围绕SLF4J方法创建了一个完整的包装器。 Github上提供了源代码, Bintray上提供了二进制工件,因此您只需要以下依赖项即可使用它:

<dependency>
  <groupId> ch.frankel.log4k </groupId>
  <artifactId> slf4k-api </artifactId>
  <version> 1.0.0 </version>
</dependency>

翻译自: https://blog.frankel.ch/smart-logging-in-java8-kotlin/

kotlin 和java

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值