当前位置: 首页 > 知识库问答 >
问题:

科特林测井的惯用方式

艾修然
2023-03-14
public class Foo {
    private static final Logger LOG = LoggerFactory.getLogger(Foo.class);
}

共有1个答案

陆建木
2023-03-14

在大多数成熟的Kotlin代码中,您会发现下面的模式之一。使用属性委托的方法利用了Kotlin生成最小代码的能力。

注意:这里的代码用于java.util.logging,但同样的理论适用于任何日志库

类静态(常见,相当于问题中的Java代码)

class MyClass {
    companion object {
        val LOG = Logger.getLogger(MyClass::class.java.name) 
    }

    fun foo() {
        LOG.warning("Hello from MyClass")
    }
}  

关于同伴对象的更多信息:同伴对象...还请注意,在上面的示例中,MyClass::Class.java为记录器获取类型的实例,而this.javaclass将获取类型的实例。

类的每个实例(公共)

但是,确实没有理由避免在实例级别调用和获取记录器。您提到的惯用Java方式已经过时,并且基于对性能的恐惧,而每个类的记录器已经被地球上几乎任何合理的日志html" target="_blank">系统缓存。只需创建一个成员来保存记录器对象。

class MyClass {
  val LOG = Logger.getLogger(this.javaClass.name)

  fun foo() {
        LOG.warning("Hello from MyClass")
  }
} 

2015年12月26日上午11:28:44 org.stackoverflow.kotlin.test.MyClass foo信息:来自MyClass的你好

您可以测试每个实例和每个类的性能变化,看看大多数应用程序是否存在实际差异。

属性委托(常见的,最优雅的)

fun <R : Any> R.logger(): Lazy<Logger> {
    return lazy { Logger.getLogger(unwrapCompanionClass(this.javaClass).name) }
}
// see code for unwrapCompanionClass() below in "Putting it all Together section"
class Something {
    val LOG by logger()

    fun foo() {
        LOG.info("Hello from Something")
    }
}

对于每个类实例,或者如果您希望它更加静态,每个类只有一个实例:

class SomethingElse {
    companion object {
        val LOG by logger()

    }

    fun foo() {
        LOG.info("Hello from SomethingElse")
    }
}

对这两个类调用foo()的输出是:

2015年12月26日上午11:30:55 org.stackoverflow.kotlin.test.Something foo信息:Hellow from Something

// extend any class with the ability to get a logger
fun <T: Any> T.logger(): Logger {
     return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
}

现在,在一个类(或伴生对象)中,我可以简单地在我自己的类上调用这个扩展:

class SomethingDifferent {
    val LOG = logger()

    fun foo() {
        LOG.info("Hello from SomethingDifferent")
    }
}

产生产出的:

2015年12月26日上午11:29:12 org.stackoverflow.kotlin.test.SomethingDifferent foo info:来自SomethingDifferent的你好

val LOG1 = "".logger()
val LOG2 = Date().logger()
val LOG3 = 123.logger()

标记界面上的扩展函数(不确定有多常见,但“特征”的常见模型)

为了使扩展的使用更干净并减少“污染”,您可以使用标记接口来扩展:

interface Loggable {} 

fun Loggable.logger(): Logger {
     return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
}    

甚至使用默认实现使方法成为接口的一部分:

interface Loggable {
    public fun logger(): Logger {
        return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
    }
}
class MarkedClass: Loggable {
    val LOG = logger()
}
interface Loggable {
    val LOG: Logger  // abstract required field

    public fun logger(): Logger {
        return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
    }
}

现在接口的实现者必须如下所示:

class MarkedClass: Loggable {
    override val LOG: Logger = logger()
}

当然,抽象基类也可以这样做,既可以选择接口,也可以选择实现该接口的抽象类,从而允许灵活性和统一性:

abstract class WithLogging: Loggable {
    override val LOG: Logger = logger()
}

// using the logging from the base class
class MyClass1: WithLogging() {
    // ... already has logging!
}

// providing own logging compatible with marker interface
class MyClass2: ImportantBaseClass(), Loggable {
    // ... has logging that we can understand, but doesn't change my hierarchy
    override val LOG: Logger = logger()
}

// providing logging from the base class via a companion object so our class hierarchy is not affected
class MyClass3: ImportantBaseClass() {
    companion object : WithLogging() {
       // we have the LOG property now!
    }
}

把它放在一起(一个小助手库)

// Return logger for Java class, if companion object fix the name
fun <T: Any> logger(forClass: Class<T>): Logger {
    return Logger.getLogger(unwrapCompanionClass(forClass).name)
}

// unwrap companion class to enclosing class given a Java Class
fun <T : Any> unwrapCompanionClass(ofClass: Class<T>): Class<*> { 
   return ofClass.enclosingClass?.takeIf { 
      ofClass.enclosingClass.kotlin.companionObject?.java == ofClass 
   } ?: ofClass 
}

// unwrap companion class to enclosing class given a Kotlin Class
fun <T: Any> unwrapCompanionClass(ofClass: KClass<T>): KClass<*> {
   return unwrapCompanionClass(ofClass.java).kotlin
}

// Return logger for Kotlin class
fun <T: Any> logger(forClass: KClass<T>): Logger {
    return logger(forClass.java)
}

// return logger from extended class (or the enclosing class)
fun <T: Any> T.logger(): Logger {
    return logger(this.javaClass)
}

// return a lazy logger property delegate for enclosing class
fun <R : Any> R.lazyLogger(): Lazy<Logger> {
    return lazy { logger(this.javaClass) }
}

// return a logger property delegate for enclosing class
fun <R : Any> R.injectLogger(): Lazy<Logger> {
    return lazyOf(logger(this.javaClass))
}

// marker interface and related extension (remove extension for Any.logger() in favour of this)
interface Loggable {}
fun Loggable.logger(): Logger = logger(this.javaClass)

// abstract base class to provide logging, intended for companion objects more than classes but works for either
abstract class WithLogging: Loggable {
    val LOG = logger()
}

选择你想保留的任何一个,下面是所有正在使用的选项:

class MixedBagOfTricks {
    companion object {
        val LOG1 by lazyLogger()          // lazy delegate, 1 instance per class
        val LOG2 by injectLogger()        // immediate, 1 instance per class
        val LOG3 = logger()               // immediate, 1 instance per class
        val LOG4 = logger(this.javaClass) // immediate, 1 instance per class
    }

    val LOG5 by lazyLogger()              // lazy delegate, 1 per instance of class
    val LOG6 by injectLogger()            // immediate, 1 per instance of class
    val LOG7 = logger()                   // immediate, 1 per instance of class
    val LOG8 = logger(this.javaClass)     // immediate, 1 instance per class
}

val LOG9 = logger(MixedBagOfTricks::class)  // top level variable in package

// or alternative for marker interface in class
class MixedBagOfTricks : Loggable {
    val LOG10 = logger()
}

// or alternative for marker interface in companion object of class
class MixedBagOfTricks {
    companion object : Loggable {
        val LOG11 = logger()
    }
}

// or alternative for abstract base class for companion object of class
class MixedBagOfTricks {
    companion object: WithLogging() {} // instance 12

    fun foo() {
       LOG.info("Hello from MixedBagOfTricks")
    }
}

// or alternative for abstract base class for our actual class
class MixedBagOfTricks : WithLogging() { // instance 13
    fun foo() {
       LOG.info("Hello from MixedBagOfTricks")
    }
}

本示例中创建的所有13个记录器实例都将生成相同的记录器名称,并输出:

2015年12月26日上午11:39:00 org.stackoverflow.kotlin.test.mixedbagofticles foo信息:来自mixedbagofticles的你好

 类似资料:
  • 如何在使用Kotlin的Spring Boot中正确初始化ConfigurationProperties? 目前我喜欢下面的例子: 但是它看起来很丑陋,实际上不是一个iable,foo是常量ue,应该在启动期间初始化,将来不会改变。

  • 问题内容: 我正在学习具有C ++和Java背景的Kotlin。我期待下面的打印,不。我知道这对应到。默认实现不比较每个成员,即和吗?如果是这样,它会不会看到字符串值相等(因为再次映射到字符串值)?显然,我在Kotlin中还没有涉及平等与身份相关的问题。 问题答案: 您描述的默认实现仅适用于数据类。不适用于从中继承实现的常规类,只需使对象与自身相等即可。

  • 这是正确的吗? 我可以找到一个相关的问题,但它是有参数的,我不能在没有params的情况下转换它。

  • 我正在尝试IntDef typedef将特定类型的参数限制为函数。但是当我使用Java使用IntDef时,它工作正常,但同时,它不适用于kotlin。以下是我的代码片段 - 在JAVA中- 在静态编程语言中- 在课堂上使用- 调用演示函数给我一个错误消息,说它必须是:< code>TransTypeJava之一。CASH,< code>TransTypeJava。通过传递< code>TransT