函数定义和调用
- 处理集合、字符串和正则表达式函数
- 使用命名参数、默认参数,以及中缀调用的语法
- 通过拓展函数和属性来适配Java库
- 使用顶层函数、局部函数和属性架构代码
创建集合
val set = hashSetOf(1, 2, 3, 44, 32)
val arraylist = arrayListOf(1, 5, 67)
val map = hashMapOf(1 to "one", 2 to "two", 7 to "seven")//这里的to是一个普通函数
可以通过命名参数名
fun <T> joinToString(
collection: Collection<T>,
seperator: String,
prefix: String,
postfix: String
): String {
val result = StringBuilder(prefix)
for ((index, element) in collection.withIndex()) {
if (index>0) result.append(seperator)
result.append(element)
}
result.append(postfix)
return result.toString()
}
//调用
//可以指定参数名称
println(joinToString(collection = arrayListOf, seperator = ";", prefix = "-", postfix = ""))
可以制定默认参数
fun <T> joinToString(
collection: Collection<T>,
seperator: String = "",//指定一个默认参数,调用可以不写这个参数
prefix: String = "",
postfix: String = ""
): String {
val result = StringBuilder(prefix)
for ((index, element) in collection.withIndex()) {
if (index>0) result.append(seperator)
result.append(element)
}
result.append(postfix)
return result.toString()
}
//调用
println(joinToString(collection = arrayListOf, seperator = ";", prefix = "-"))
顶层函数和属性-》这个可以消除静态工具类(utils类)
- 顶层函数
//文件名为join.kt
package strings
fun joinToString() = ""
//在Java中调用
JoinKt.joinToString()
//修改文件名需要添加一个注解
package strings
//改变文件命名,使用Java调用StringFunctions.joinToString()
@file:JvmName("StringFunctions")
fun joinToString() = ""
- 顶层属性 ->静态函数static
var oPcount = 0
val UNIX_LINE = "1"
//转换成Java
public static int oPcount = 0
public static final String UNIX_LINE = "1"
注意:顶层属性不是特别常用
拓展函数和属性 这个可以给别人的类添加方法,比较碉堡
举个栗子:
package strings
fun String.lastChar() = this[length-1]
//调用
fun main(args: Array<String>) {
println("Kotlin".lastChar())
}
拓展函数不能访问私有或者受保护的方法、属性
- 导入和拓展函数
//可以使用as来修改导入函数类或者函数名称,
import strings.lastChar as last
val c = "Kotlin".last()
在有重名函数,就显得特别重要了
- 拓展函数本质
拓展函数就是静态函数,在Java中调用也很简单
char c = StringUtils.lastCar("Kotlin")//其中StringUtils为顶级函数文件名
因为是顶层函数,所以会编译成一个静态函数,在Java中也是静态导入lastCar()函数
- 拓展函数不可重写
fun View.showOff() = print("I'm a View")
fun Button.showOff() = print("I'm a Button")
fun main(args: Array<String>) {
println("Kotlin".lastChar())
val button:View = Button()
button.click()//显示 View click
button.showOff() //显示 I'm a View
}
open class View {
open fun click() = print("View click")
}
class Button : View(){
override fun click() {
print("Button click")
}
}
拓展属性
kotlin可以吧一个方法转换成一个属性调用
val String.lastChar get() = get(length - 1)
//调用
fun main(args: Array<String>) {
println("Kotlin".lastChar)//得出结果 n
}
var StringBuilder.lastChar: Char //这里"Char"省略也可以,已经根据get()判断出类型
get() = get(length - 1)
set(value: Char) = setCharAt(length - 1, value) //这里"Char"省略也可以,已经根据get()判断出类型
可变参数、中缀调用和库支持
- 关键字vararg 声明参数的个数是可变的
fun getString(vararg str: String): String = ""
- 中缀调用(需要添加关键字infix)->在调用一些只有参数的函数,可以让代码更简洁
val stringsMap = mapOf(1.to("1"), 2.to("22"), 33.to(99)) //使用普通函数调用
val stringsMap = mapOf(1 to "1",2 to "22",33 to "99") //使用中缀调用
//这里是等价的
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
//这里我们可以直接初始化这个对象
val(index,value) = 1 to "11"
//通常我们会这样写
val StringMap = 1 to "11"
- 解构声明->用来把一个单独的组合值展开到多个变量中。结合上面代码,如下图:

for ((index,value) in strings.withIndex()){
print(index)
println(value)
}
简化字符串和正则操作
- 分割字符串
kotlin的字符串分割更加强大,kotlin的split函数调用的不是Java中的函数。
通常我们会这样写
val listStr = "12.345-6.A".split(".") //会等到一个list [12, 345-6, A]
在kotlin中,你还可以这样写
val listStr = "12.345-6.A".split(".","-") //会等到一个list [12, 345, 6, A]
//解析字符串
val dirPath = path.substringBeforeLast("/")
val fileName = path.substringAfterLast("/")
var file = fileName.substringBefore(".")
var fileEx = fileName.substringAfter(".")
println("文件路径:$dirPath 文件名:$fileName 文件类型:$fileEx")
//得到的结果:
文件路径:/root/home 文件名:kotlin.kt 文件类型:kt
- 正则(正则表达式写在一个三重引号的字符串中)eg:
"""(.+)/(.+)\.(.+)"""
三行字符串引号之间的所有字符,包括格式代码缩进、换行等
局部函数和拓展
当我们需要校验实体数据是否有效可以这样写
class User(var name: String,var age: Int,var address: String)
fun saveUser(user: User){
fun valueData(name: String){
if (name.isEmpty()) {
throw IllegalArgumentException(
"Can't save user data"
)
}
}
valueData(user.name)
}
我们还可以这样优化
fun User.valueDataBeforSave() {
fun valueData(value:String) {
if (value.isEmpty()) {
throw IllegalArgumentException(
"Can't save user data"
)
}
}
valueData(name)
valueData(address)
}
//调用
fun saveUser(user: User) {
user.valueDataBeforSave()
}
接口中的属性声明
interface User {
val email: String
val nickName: String
get() = email.substringBefore("@")//在接口中直接获取
}
class SubscribeUser(override val email: String) :User
通过getter和setter访问支持字段
class User(private val name: String) {
var address: String = "unspecified"
set(value) {
println("""
Address is change for $name
$field -> $value //在set方法中,field代表当前值
""".trimIndent())
field = value
}
}
//调用
User("Bob").address = "广东省广州市天河区珠江新村" //这里的赋值,底层是调用了setter方法
getter和setter设置可见性
class LengthCounter {
var countor: Int = 0
private set //只能在本类中设置
fun addWord(word: String): LengthCounter {
countor += word.length
return this
}
}
//调用
val lengthCounter = LengthCounter()
lengthCounter.addWord("哈哈哈,王小丫")
.addWord("yyyyy,gggg")
println("已添加的字符串长度:${lengthCounter.conter}")
创建对象类和类委托
创建数据类使用data关键字修饰该类
对象类会自动生成一些模版方法,比如equls()、hashCode()、toString()等方法
注意:在kotlin 使用==表示相等性 类似于Java的equls,使用===比较引用是否相等
data class Client(val name: String,val postCode: Int)
//这里会自动会生成
//equls()
//toString()
//hashCode()
这里的equls hashCode会把所有在主函数中的参数都实现注意:如果主函数没有实现,则不会比较
- 数据类的不可变性
copy()方法\
val client = Client("Bob",510000)
val clientCopy = client.copy()
创建副本是修改实例的好选择
类委托 使用关键字 by
当我们需要向一些类添加一些行为,会使用装饰者模式(本质就是创建一个新类,实现与原始类一样的接口,并且将原来的类保存成一个字段)