kotlin常用语法扫盲及开发注意点,勿错失(持续更新)
发布日期:2021-06-29 14:16:14 浏览次数:2 分类:技术文章

本文共 8976 字,大约阅读时间需要 29 分钟。

kotlin常用语法扫盲及开发注意点,勿错失(持续更新)

文章目录

单句表达式 可以直接 用 = 省略 大括号

// 比较常规易懂的 写法fun  (a :Int , b : Int):Int{   return a + b}// 单句表达式 可以直接 用 = 省略 大括号fun  (a :Int , b : Int):Int = a + b// 智能类型fun  (a :Int , b : Int) = a + b

::双冒号作用

双冒号操作符 表示把一个方法当做一个参数,传递到另一个方法中进行使用,通俗的来讲就是引用一个方法。

在kotlin里可以直接引用方法名当参数使用。
例如

fun main(args: Array
) { println(testFun("hello", "world!", ::getResult))}fun getResult(str1: String, str2: String): String = "result is {$str1 , $str2}"fun testFun(p1: String, p2: String, method: (str1: String, str2: String) -> String): String { return method(p1, p2)}

总结

直接引用getResult方法当参数使用传入testFun方法里,可以在testFun方法里直接调用。
注意引用的函数类型要匹配,或者说要确定参数个数、类型、返回值都和其形参一致。
输入结果:result is {hello, world}

map,list使用

经常使用map和list集合,set很少使用。

只读map

Map也分为只读map和可变两种Map(mutableMap)。实际是MutableMap继承自Map,是它的子类,扩展的增加/修改/删除操作。

Kotlin建议使用Map和MutableMap,不建议使用HashMap。
map创建

val map= mapOf
("name" to "cy", "age" to "12")

创建之后,定长,不能删除和修改。

map取值

mapp.getValue("name")或mapp["name"]2者相当

map遍历

for ((k,v) in map){    println("$k -> $v")}

可变MutableMap

创建MutableMap

val mcc:MutableMap
= mutableMapOf
("name" to "cy", "age" to "12")

创建之后,可以删除和删除。如下

mcc.put("address", "china")        mcc.remove("address")

遍历

Map和MutableMap遍历方式都一样的。

遍历key

for (key in map.keys) { Log.i("tag","key = $key") }

遍历value

for (value in map.values) { Log.i("tag","value = $value") }

遍历整个结构点

方式一

for ((k,v) in map){    println("$k -> $v")}

k是键,v是值的意思,2个都可以自己命名,取值使用$k$v

方式二

val setEntry = map.entriessetEntry.forEach{    println("key: ${it.key} , value: ${it.value}")}

list

list和map类似,也分为只读List和可变两种List(mutableList)。

只读list

创建

val testList= listOf
("name", "age","address")

遍历

val items = listOf("apple", "banana", "kiwi")

方式一for循环

  1. 遍历value
for (nm in testList) {    println(nm)}
  1. 遍历index
for(index in testList.indices){	print(testList[i])}
  1. 遍历index和value
for((index, value) in testList.withIndex()){	println("the element at $index is $value")}

方式二迭代器

val ite:Iterator = testList.iterator()
while (iterator.hasNext()) {
println(iterator.next())
}

方式三lamdba表达式

val arrayDouble = testList.map(value -> println(value))

如果括号中的参数只有一个,那么完全可以省略括号,同时其变量可以用it来代替,还可省略“->”,如下

val arrayDouble = testList.map(println(it.value))

常用的数组、集合、序列等数据结构的扩展函数

##filter()

val list = listOf(1, 2, 3);var filterList = list.filter(it >=2 );pritln(filterList)

结果为:2,3

函数作用是过滤,接收函数作为参数,遍历集合每个元素,将符合条件的元素重新封装到一个集合里返回。

map()

映射,用于转化数据或者说计算新数据,遍历每个元素,根据传入的函数计算一个新值组成新的集合返回给变量

val list = listOf(1, 2, 3);var filterList = list.map(it *2 );pritln(filterList)

输出结果:2,4,6

泛型函数

泛型就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

kotlin类可以指定泛型

class Box
(t: T) { var value = t}

使用时传入具体类型即可

val box: Box
= Box
(1)

泛型函数即在函数前加上泛型,比如kotlin里let函数的申请如下

public inline fun 
T.let(block: (T) -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block(this)}

T和R是后面函数里传入的参数类型,要调用泛型函数,在调用处函数名之后指定类型参数即可。

this.let
()

泛型函数常见去标准库源码里。

常见内联函数

参考

let函数

是个内联函数,源码定义是

public inline fun 
T.let(block: (T) -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block(this)}

接收一个函数做为参数,说明let是高阶函数,同时接收的函数类型用lambda表达式指定,将T类型值转换成R类型值。

我们知道它是一个泛型函数,一般能通过kotlin的智能推算知道T和R的类型,所以使用let函数时不指定类型。

一般在let后面直接跟上block代码块,在函数块内可以通过 it 指代该对象。返回值为函数块的最后一行或指定return表达式。

let函数可以使用在任何对象上。

let函数在如下2种情况下使用

  • 最常用的场景就是使用let函数处理需要针对一个可null的对象统一做判空处理
  • 然后就是需要去明确一个变量所处特定的作用域范围内可以使用

使用示例

//表示object不为null的条件下,才会去执行let函数体object?.let{it.todo()...}//在函数体内使用it替代object对象去访问其公有的属性和方法object.let{it.todo()...}

with函数

标准语法

with(object,{   //todo })

with函数一般使用结构,因为函数体是是后一个参数,可以放在外面。

with(object){   //todo }

它是将某对象作为函数的参数,在函数块内可以通过 this 指代该对象,可以在函数体内直接使用对象属性和方法。返回值为函数块的最后一行或指定return表达式。

但是它没有做判空操作,需要手动判空。

适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类的方法即可。

与let区别

  • 函数体内部使用this代表对象,而不是it
  • 没有做判空操作,需要手动判空。
  • 使用的地方不是很多

run

run函数使用的一般结构

object.run{//todo}//判空object?.run{//todo}

run函数实际上可以说是let和with两个函数的结合体,适用于let,with函数任何场景。它弥补了let函数在函数体内必须使用it参数替代对象,在run函数中可以像with函数一样可以省略,直接访问实例的公有属性和方法,另一方面它弥补了with函数传入对象判空问题,在run函数中可以像let函数一样做判空处理。

返回值为函数块的最后一行或指定return表达式。

apply

run函数使用的一般结构

object.apply{//todo}//判空object?.apply{//todo}

看apply函数和run函数很像,唯一不同点就是它们各自返回的值不一样,run函数是以闭包形式返回最后一行代码的值,而apply函数的返回的是传入对象的本身。

区别

Tables Are Cool
col 3 is right-aligned $1600
col 2 is centered $12
zebra stripes are neat $1
函数名 定义inline的结构 函数体内使用的对象 返回值 是否是扩展函数 适用的场景
let fun T.let(block: (T) -> R): R = block(this) it指代当前对象 闭包形式返回 适用于处理不为null的操作场景
with fun with(receiver: T, block: T.() -> R): R = receiver.block() this指代当前对象或者省略 闭包形式返回 适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类的方法即可,经常用于Android中RecyclerView中onBinderViewHolder中,数据model的属性映射到UI上
run fun T.run(block: T.() -> R): R = block() this指代当前对象或者省略 闭包形式返回 适用于let,with函数任何场景。
apply fun T.apply(block: T.() -> Unit): T { block(); return this } this指代当前对象或者省略 返回this 1、适用于run函数的任何场景,一般用于初始化一个对象实例的时候,操作对象属性,并最终返回这个对象。2、动态inflate出一个XML的View的时候需要给View绑定数据也会用到.3、一般可用于多个扩展函数链式调用 4、数据model多层级包裹判空处理的问题

Kotlin中常见的符号

参考

$符号

$ 表示一个变量名或者变量值

$varName 表示变量值
${varName.fun()} 表示变量的方法返回值
${
} 表示对象属性返回值

?符号

赋值和返回值

//在变量类型后面加上问号,代表该变量是可赋值为null,否则不能赋值为null  var name: String? = "zhangsan" //方法的返回类型后加上问号,代表方法可以返回nullfun parseInt(str: String): Int? {   // (代码略)}//b为非空,则返回b.length ,否则返回 nullb?.length

安全空访问?.

person?.name

person对象不为null时才会调用它的name属性.

Elvis操作?:符号

?:做空判断处理,可理解为三目运算符

val nullableName: String? = ...val name: String = nullableName ?: "default_name"

安全类型转换as?

如果想安全地进行类型转换, 当转换失败时结果 null, 这种情况可用 as?

val location: Any = "London"val safeString: String? = location as? Stringval safeInt: Int? = location as? Int

!!符合

这会返回一个非空的 b 值 或者如果 b 为空,就会抛出一个 NPE 异常。它与?.的区别是,!!为空为抛异常,而?.为空,不做处理返回null。(当然它可以和?:一起使用返回为null时的默认值-类似三目运算符功能)

val l = b!!.length

==号与===

==判断值是否相等,===判断值及引用地址是否完全相等。

..符合

..配合in和!in一起使用,表示区间的意思.

for(i in 1..10) { // 等同于 1 <= i && i <= 10    println(i)}//使用until函数,创建一个不包括其结束元素的区间for (i in 1 until 10) {   // i in [1, 10) 排除了 10     println(i)}// 使用 step 指定步长for (i in 1..4 step 2) {	print(i) // 输出“13”}//由大到小,使用downTofor (i in 4 downTo 1 step 2){	 print(i) // 输出“42”}

_(下划线)符合

用于对象解析时,属性的占位符

例如

data class Person(var id: Int, var name: String)val (_,name) = Person(12,"cy")

::符号

双冒号操作符 表示把一个方法当做一个参数,传递到另一个方法中进行使用,通俗的来讲就是引用一个方法。见文章开头。

@符号

在kotlin标签语法中使用。

在 Kotlin 中任何表达式都可以用标签(label)来标记。 标签的格式为标识符后跟 @ 符号,例如:abc@
标签语法经常和break和return使用,用于指定从标签处中断或从标签处返回。

//直接在loop标签处中断(最外层中断for循环)loop@ for (i in 1..100) {    for (j in 1..100) {        if (……) break@loop    }}//从lit标签处返回ints.forEach lit@ {        if (it == 0) return@lit        print(it)    }

{}符号

{}符号中定义lambda表达式

*符号

扩展符号,可以用于拼接数组

val a = arrayOf(1, 2, 3) var b = arrayOf(*a, 2) val list = asList(-1, 0, *a, 4)//或者 val c = intArrayOf(1,2,3)    val d = intArrayOf(*c, 4,5)

Lambda表达式和匿名函数

Lambda表达式和匿名函数很相似,但其实2者不相等。Lambda表达式可以称为匿名函数,但匿名函数不能称为Lambda表达式。

kotlin代码

fun compare(a: Int, b: Int): Int{    return a +b}add(::compare)

计算2者和。

  • 修改为匿名函数
fun compare(a: Int, b: Int): Int{    return a +b}add((a,b)->{a+b})
  • 修改为Lambda表达式
fun compare(a: Int, b: Int): Int{    return a +b}add({(a,b)->a+b})

如果没有入参数,前面的括号可以去掉。比如add({a+b})

Lambda表达式满足以下条件即可。

  • 一般使用“{ }”包围。
  • 它的参数(如果有的话)在“->”前定义,参数类型可能是省略的。
  • 函数体跟在“->”后面。
  • 返回值是最一个语句值,或显示使用return指定的值
    匿名函数只是省略了函数名,但整个函数结构并不是被大括号{}包裹的。所以匿名函数不是Lambda表达式。

高阶函数

高阶函数是将函数作为参数或返回一个函数。可以使用Lambda表达式和匿名函数。

上面的add函数就是高阶函数。如下

fun add(cc:(a,b)->a +b){	cc()}

指定函数类型的入参类型和返回类型。

常见的高阶函数除了上面介绍的let,run,with,apply外还有下面的。

val oldList = listOf(1, 2, 3, 4, 5)val newList = ArrayList
()//forEach 遍历--高阶函数oldList.forEach { val newElement = it * 2 + 3 newList.add(newElement)}//map映射返回新的集合--高阶函数val newList1 = oldList.map { it * 2 + 3}//filter 过滤返回新的集合--高阶函数val newList5 = oldList.filter { it == 2 || it == 4}

object,data关键字

object

使用object代替class用于声明单例对象,单例对象第一次使用时被创造出来。

比如如下,声明Privilege单例,单例名就是Privilege。

object Privilege {    val READ = "read"    val WRITE = "write"}

使用方法如下

Privilege.READPrivilege.WRITE

基本使用情况就如上面,大部分情况掌握上面即可。如果深入学习,我们发现object也会与compain组合使用,也就是伴生对象。具体参考

data数据类

一般而言,我们在Java中定义了这个数据类之后要重写一下toString,equals等方法。要生成get,set方法。然而在Kotlin中使用数据类系统自动帮我们实现。

有一下几点要求:

  • 主构造函数必须要至少有一个参数
  • 主构造函数中的所有参数必须被标记为val或者var
  • 数据类不能有以下修饰符:abstract,inner,open,sealed
  • data class只能实现接口(Kotlin1.1以前的规则),现在也可以继承其它类

例子

data class User(var id: Int, var name: String)

注意生成的equals()函数和==作用类似。==比较的是对象里值是否相等,===比较的是对象地址是否相等

isXXX生成的gettter和setter方法

lotlin里比如如下变量生成的getter和setter为

var groupName: String = ""//自动生成的getter和setter为@NotNull public final String getGroupName() {   return this.groupName; }  public final void setGroupName(@NotNull String 
) { Intrinsics.checkParameterIsNotNull(
, "
");this.groupName =
; }

但isXXX字段生成的getter和setter是不一样的

var isProject: Boolean = false//自动生成的getter和setter为public final boolean isProject() {   return this.isProject; }  public final void setProject(boolean 
) { this.isProject =
; }

所以当我们定义isXXX变量时,接收的字段其实是XXX,比如上面我们定义的isProject,其实setter方法是setProject,所以传递的参数是project而不是isProject

转载地址:https://chenyuan.blog.csdn.net/article/details/80774135 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:spring-data-jpa使用,方便却又不方便的ORM框架
下一篇:模块开发之ant(Ant Design of React)使用(四)

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月28日 13时31分44秒