使用表达式
不建议:
fun getDefaultSex(name:String):User{
if(name=="mike"||name=="jack"){
return male;
}
if(name="marry"||name="jane"){
return female
}
return male
}
建议:
fun getDefaultSex(name:String)=when(name){
"mike","jack"->male
"marry","jane"->female
else->male
}
每次使用if的时候都考虑一下,表达式是否可以用更简洁的方式代替。
try-catch也是一个表达式:
var string=""
string=try{
return "Ok"
}catch(e:Exception){
return "Error"
}
扩展函数
在Java中,我们经常在Util类中创建静态Util方法。这种模式翻译成Kotlin将如下所示:
不建议:
object StringUtils{
fun countNum(num:Int):Int{
return num*2
}
}
StringUtils.countNum(3)
Kotlin允许移除不必要的包装类,并使用扩展函数。通常我们还可以利用扩展函数来挺高可读性。
建议:
fun Int.countNum():Int{
return plus(2)
}
3.countNum()
输出结果:
5
变量名代替Setter
在Java中,我们常为变量添加getter/setter方法,这样就会有大量的模板代码。
不建议:
val params=User()
.setName("android coder")
.setAge(25)
.setSex("male")
在Kotlin中,命名和默认参数可以直接赋值:
建议:
val params=User(name="android coder",age=25,sex="male")
apply()为Grouping Object初始化
不建议:
val user=User()
user.Name="android code"
user.age=25
user.sex=male
user.isDream=true
扩展函数apply()可以对对象的初始化代码进行分组和集中。这样,我们就不必一遍一遍的重复变量名称了。
建议:
val user=User().apply{
name="android coder"
age=25
sex="male"
isDream=true
}
当处理Java类时apply()往往会很有用
不要重载默认构造函数
不要重载方法和构造函数来实现默认参数
不建议:
fun user(name:String){
user(name,true)
}
fun find(name:String,isDream:Boolean){
}
建议:
fun user(name:String,isDream:Boolean=true){
}
事实上,默认参数几乎取代了方法和构造函数重载的写法,因为,重载主要用于创建默认函数。
清晰简单处理NULL
避免if-null检查
不建议:
if(user==null||user.name==null||user.age==null){
throw IllegalArgumentException("Invalid User")
}
val name=user.name
每次我们都要写一个if-null检查。Kotlin提供了更好的方法来处理空值。使用as?和?:来检查类型,如果不是我们需要的,则抛出一个异常
建议:
user as? VIPUser ?:throw IllegalArgumentException("NO VIP")
user.getVIP()
避免not-null断言!!
不建议:
user!!.vip!!.name!!.address!!
双重感叹号看起来会让你很烦。这是故意这么设计的,Kotlin的设计者正试着让你朝着一个更好的方向发展,而这个解决方案并不涉及编译器无法验证的断言。来源于:“Kotlin in Action”--->Dmitry Jemerov和Svetlana Isakova。
考虑使用let()
有时候,let()可以是if的简洁版。但是,你必须以合理的方式来使用它,以免出现问题。
val user:User?=findUser()
if(user!=null){
println(user.name)
}
当使用let()时,不需要额外的变量
class findUser{
val name:String="
}
findUser()?.let{println(it.name)}
//或者
findUser()?.customer?.let(::print)
简单的单表达函数映射
不建议:
fun mapToDTO(entity: SnippetEntity): SnippetDTO {
val dto = SnippetDTO(
code = entity.code,
date = entity.date,
author = "${entity.author.firstName} ${entity.author.lastName}"
)
return dto
}
使用单个表达式函数和命名参数,我们可以在对象之间编写简单,简洁和可读的映射。
建议:
fun mapToDTO(entity: SnippetEntity) = SnippetDTO(
code = entity.code,
date = entity.date,
author = "${entity.author.firstName} ${entity.author.lastName}"
)
val dto = mapToDTO(entity)
如果你对扩展功能熟悉,你可以在这里使用它们来使函数定义和使用更短,更易读。同时,我们不会用映射逻辑来破坏value对象
fun SnippetEntity.toDTO() = SnippetDTO(
code = code,
date = date,
author = "${author.firstName} ${author.lastName}"
)
val dto = entity.toDTO()
在Property Initializers时参考构造函数参数
不建议:
class UsersClient(baseUrl: String, appName: String) {
private val usersUrl: String
private val httpClient: HttpClient
init {
usersUrl = "$baseUrl/users"
val builder = HttpClientBuilder.create()
builder.setUserAgent(appName)
builder.setConnectionTimeToLive(10, TimeUnit.SECONDS)
httpClient = builder.build()
}
fun getUsers(){
//call service using httpClient and usersUrl
}
}
我们可以在属性初始化时引用主构造函数(而不是在init块中)。apply()可以帮助初始化代码分组。
class UsersClient(baseUrl: String, appName: String) {
private val usersUrl = "$baseUrl/users"
private val httpClient = HttpClientBuilder.create().apply {
setUserAgent(appName)
setConnectionTimeToLive(10, TimeUnit.SECONDS)
}.build()
fun getUsers(){
//call service using httpClient and usersUrl
}
}
解构
一方面,解构对于从一个函数返回多个值是很有用的。我们可以定义一个自己的数据类,或者使用Pair。
data class User(name:String,age:Int)
fun createUser:User{
return User("android coder",25)
}
//使用解构
val (name,age)=createUser()
另一方面,解构可以用于map映射
val map=mapOf("android coder" to name,25 to age)
for((name,age) in map){
//do something
}
创建特殊的结构
listOf、mapOf、和infix函数可以用来创建JSON。
val user=mapOf(
"name" to "android coder",
"age" to 25,
"language" to listOf("chinese","english")
"address" to mapOf(
"city" to "china"
"pronvice" to "beijing"
"street" to "chaoyang"
)
)
通常我们应该使用数据类和对象映射来创建JSON。但有时(例如在测试中)这是非常有用的。