kotlin 学习笔记03

160 阅读5分钟

函数定义和调用

  • 处理集合、字符串和正则表达式函数
  • 使用命名参数、默认参数,以及中缀调用的语法
  • 通过拓展函数和属性来适配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循环中看到这样的代码

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


通过gettersetter访问支持字段

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方法

gettersetter设置可见性

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

当我们需要向一些类添加一些行为,会使用装饰者模式(本质就是创建一个新类,实现与原始类一样的接口,并且将原来的类保存成一个字段)