虽然lateinit对于自动装配很有用,但我建议谨慎地使用它。另一方面,它会关闭属性上的编译时空检查。如果在第一次使用时是null仍然会出现运行时错误,但是会丢失很多编译时空检查。
构造函数注入可以作为一种替代方法。这与Spring DI可以很好地配合,并消除了许多混乱。例如:
@Component class MyService constructor(val config: SessionConfig)这是Kotlin引导你遵循最佳实践的一个很好的例子。
HibernateHibernate和Kotlin可以很好地搭配使用,不需要做大的修改。一个典型的实体类如下所示:
@Entity @Table(name = "device_model") class Device { @Id @Column(name = "deviceId") var deviceId: String? = null @Column(unique = true) @Type(type = "encryptedString") var modelNumber = "AC-100" override fun toString(): String = "Device(id=$id, channelId=$modelNumber)" override fun equals(other: Any?) = other is Device && other.deviceId?.length == this.deviceId?.length && other.modelNumber == this.modelNumber override fun hashCode(): Int { var result = deviceId?.hashCode() ?: 0 result = 31 * result + modelNumber.hashCode() return result } }在上面的代码片段中,我们利用了几个Kotlin特性:
属性
通过使用属性语法,我们就不必显式地定义getter和setter了。这减少了混乱,使我们能够专注于数据模型。
类型推断
在我们可以提供初始值的情况下,我们可以跳过类型规范,因为它可以被推断出来。例如:
var modelNumber = "AC-100"modelNumber属性会被推断为String类型。
表达式
如果我们稍微仔细地看下toString()方法,就会发现它有与Java有一些不同:
override fun toString(): String = "Device(id=$id, channelId=$modelNumber)"它没有返回语句。这里,我们使用了Kotlin表达式。对于返回单个表达式的函数,我们可以省略花括号,通过等号赋值。
字符串模板
"Device(id=$id, channelId=$modelNumber)"在这里,我们可以更自然地使用模板。Kotlin允许在任何字符串中嵌入${表达式}。这消除了笨拙的连接或对String.format等外部辅助程序的依赖。
相等测试
在equals方法中,你可能已经注意到了这个表达式:
other.deviceId?.length == this.deviceId?.length它用==符号比较两个字符串。在Java中,这是一个长期存在的问题,它将字符串视为相等测试的特殊情况。Kotlin最终修复了这个问题,始终把==用于结构相等测试(Java中的equals())。把===用于引用相等检查。
数据类
Kotlin还提供一种特殊类型的类,称为数据类。当类的主要目的是保存数据时,这些类就特别适合。数据类会自动生成equals()、hashCode()和toString()方法,进一步减少了样板文件。
有了数据类,我们的最后一个示例就可以改成:
@Entity @Table(name = "device_model") data class Device2( @Id @Column(name = "deviceId") var deviceId: String? = null, @Column(unique = true) @Type(type = "encryptedString") var modelNumber: String = "AC-100" )这两个属性都作为构造函数的参数传入。equals、hashCode和toString是由数据类提供的。