前言: 用了 kotlin
差不多半年时间了,之前是看了中文版的 kotlin
入门的,后面使用的时候总感觉有些细节的东西并没有很好的理解,专门买了份 kotlin
的教程,感觉不错,本文也是中途一些细节的整理。
var
用 lateinit
延迟初始化, val
用 lazy
延迟初始化 ?
表示可空类型,类型后面不跟 ?
表示不可空类型 ?.
表示若为 null
,则返回 null
,否则返回返回对象继续逻辑操作。 !!.
表示强制认定为不为 null
使用但是最好自己做一下判断,不然等下抛空异常 ?:
表示当前面为 null
的时候,返回 ?:
后面的值 class X lateinit var mStr:String //var 延迟初始化 val x:X by lazy{ // val延迟初始化 X() } var name: String? = "" fun a(x: Any): Int { return name?.length ?: 0 } val nullable:String? = null //正确 可以为空 val notNull:String = null //报错 不能为空 nullable.length //错误 ,不可以直接使用 notNull.length //正确,不可空的值可以直接使用 nullable!!.length //正确,强认定不为null nullable?.length //正确,若nullable为空 nullable?.length ?: -1 复制代码
as
类型转换 跟java的类型转换一样,失败则抛异常 as?
安全类型转换,转换失败返回null,不会抛异常
val stub:Childen = parent as Childen //转换失败 stub不会返回空,会抛异常 val stub:Childen = parent as? Childen //转换失败 stub 可以返回空 复制代码
ClosedRange
的子类, IntRange
最用
0..100
表示 [0,100]
0 until 100
表示 [0,100)
i in 0..100
判断是否在区间 [0,100]
中 val range:IntRange = 0..1024 //[0,1024] val range_exclusive:IntRange = 0 until 1024 //[0,1024) = [0,1023] val emptyRange:IntRange = 0...-1 //空区间 emptyRange.isEmpty() //判断区间是否为空 //迭代 for(i in range) 复制代码
基本写法: val array:Array<类型> = arrayOf(类型的对象1,类型的对象2,.....) 基本操作: array[i]
:输入第 i
个成员 array[i] = 新的类型对象
给第 i
个成员赋值
array.slice()
截取 可传入 区间
eg:0..10 或者 0 until 100
array.joinToString()
转化成 String
下面是对应的参数 -- separator: CharSequence
:分隔符 默认为 ,
-- prefix: CharSequence
: 增加前缀 默认为 ""
-- postfix: CharSequence
:增加后缀 默认为 ""
-- limit: Int
:截取位置(从1开始而不是从0开始) -- truncated
:被limit截取后,后面展示什么 -- transform
: 每个元素进行处理返回处理后的数据 具体例子展示:
val arrayOfInt: IntArray = intArrayOf(1,3,5,7) val arrayOfChar: CharArray = charArrayOf('H', 'e','l','l','o','W','o','r','l','d') val arrayOfString: Array<String> = arrayOf("我", "是", "码农") fun main() { System.out.println(arrayOfString.joinToString("")) var i:IntRange = 0..100 System.out.println(arrayOfChar.slice(0..7)) var array1 = arrayOfString.joinToString("","前缀","后缀",2,"后面省略",transform = { //转换 return@joinToString it+"转换" }) var array2 = arrayOfString.joinToString("","前缀","后缀",3,"后面省略",transform = { //转换 return@joinToString it+"转换" }) println(array1) println(array2) } -------------------------------------打印出来的log 我是码农 [H, e, l, l, o, W, o, r] 前缀我转换是转换后面省略后缀 前缀我转换是转换码农转换后缀 复制代码
val TAG = "str" 并不等价与 java中的 public final String TAG = "str" 如果要等价的话 const val TAG = "str" 复制代码
具体的可以看一下反编译 val TAG = "str"
的字节码跟 public final String TAG = "str"
有什么不同~ 里面可以看到 val
虽然不可赋值,但是它并不是编译器常量,而是一个变量。也就是编译期并不是替换成常量来进行的,所以后期还是可以经过反射进行修改! 如果要像java中定义出编译期常量的话 public final String TAG = "str"
则需要使用到 const
这里反编译出来的跟 java
中的就类似了。
本质函数也是一个成员,只不过它是一段代码块
val int2Long = fun(x:Int):Long{ return x.toLong() } 复制代码
本质:匿名函数 写法:{[参数列表]->[函数体,最后一行还是返回值]} 举例: val sum = {a:Int,b:Int ->a+b}
调用: -- 用()进行调用 -- 等价于 invoke() -- eg: sum(1,2) 或者 sum.invoke(1,2)
简化: -- 函数参数参数调用是最后一位 Lambda
可以移出去 -- 函数参数只有一个 Lambda
,调用时小括号可省略 -- Lambda
只有一个参数可默认为 it
-- 入参、返回值与形参一直的函数可以用函数引用的方式作为实参传入
示例一下:
//首先 先看下Arrays里面的forEatch方法 public inline fun CharArray.forEach(action: (Char) -> Unit): Unit { for (element in this) action(element) } ------------------------------------------------- 接下来,代码中调用 --------------------------------------------------- val arrayOfChar: CharArray = charArrayOf('H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd') //最基本的调用,传入action的代码块 arrayOfChar.forEach(char ->{println(char)}) // 简化 //1. Lambda只有一个参数可默认为it arrayOfChar.forEach ({println(it)}) // 2. 函数参数参数调用是最后一位Lambda可以移出去 arrayOfChar.forEach(){pritln(it)} // 3. 函数参数只有一个Lambda,调用时小括号可省略 arrayOfChar.forEach{pritln(it)} // 4. 入参、返回值与形参一致的函数可以用函数引用的方式作为实参传入 arrayOfChar.forEach(::println) 复制代码
与 java
不同, kotlin
的操作符允许我们进行重载。重载的函数需要使用 operation
的修饰符标记 例子:
// 重写 减号的实例 class TestKotlin(var a:Int) { operator fun minus(i:Int):Int{ return a - i } } fun main() { println(TestKotlin(6) - 5) } ---------------------输入 1 复制代码
很多的操作符那些可以看一下 《Kotlin语言中文站》
infix
修饰的函数,使用时不需要 对象.方法名(参数)
,直接 对象 方法名 参数
//定义 class Book { infix fun on(palce:String){...}} //使用 Book() on "My Name" 复制代码
for
循环的 in
把鼠标点击 in
可见其循环机制实际上是 iterator
机制, hasNext()
跟 next()
,判断有没有下一个值,有就获取
下面我们自己自定义一个 MyIterator
,跟 MyIntList
来演示一下
class MyIterator(val iterator:Iterator<Int>){ operator fun next():Int{ return iterator.next() } operator fun hasNext():Boolean{ return iterator.hasNext() } } class MyIntList{ private val list = ArrayList<Int>() fun add(int:Int){ list.add(int) } fun remove(int:Int){ list.remove(int) } operator fun iterator():MyIterator{ return MyIterator(list.iterator()) } } fun main() { val list = MyIntList() list.add(1) list.add(2) list.add(3) for (i in list){ println(i) } } 复制代码2. 跳过跟终止循环(
continue
跟
break
) 跟
java
一致,跳过当前循环用
continue
,终止循环用
break
3. 多层循环嵌套的终止结合标签使用
Outter@for(...){ Inner@while(i<0){if(...)break@Outter} } 复制代码
可以定义标签,对应关键字后面加上@标签,代表跳出到对应的某一层, 举个例子:
fun main() { val list = MyIntList() list.add(1) list.add(2) list.add(3) list.add(4) list.add(5) //break到上一层 for (i in list) { print(" $i") while (true) { print(" $i") break } } println(" ") //break到制定标签 OutSide@for (i in list) { print(" $i") while (true) { print(" $i") break@OutSide } } } ---------------------打印--------------- 1 1 2 2 3 3 4 4 5 5 1 1 复制代码
if else
分支表达式等与 java
的不同点,它们作为表达式,可以用来赋值,最后一个行的数据等于 return
的数据
fun compare():Int{ val i = 10 if (i == 10 ) 1 else 0 } 复制代码
与 java
不同的是,它也是表达式,最后一行的数据也是当成要返回的值。 但是 注意下面的写法:
return try{x/y}catch(e:Exception){0}finally{...} 复制代码
先执行完 try
有异常就跑到 catch
,最后 finally
的代码会执行,最后再返回值。(如果正常返回 0
,抛异常就返回 x/y
)
所有参数都有一点: 如果传参时有歧义,需要使用具名参数
fun sum(arg1:Int = 3,arg2:Int = 2) = arg1+arg2 复制代码
给函数的实参附上形参
fun sum(arg1:Int,arg2:Int) = arg1+arg2 sum(arg1=2,arg2=3) 复制代码
某个参数可以接受多个值 与 java
不同的是,它可以不用做最后一个参数, kotlin
支持具名函数,所以它可以放在参数中任意位置。
fun hello (vararg ints:Int,string:String){ ints.forEach(::println)} 使用: hello(1,2,3,4,string="Hello") 复制代码
*变量名
) 应用场景: 只支持展开Array,只用于变长参数列表的实参,不能重载,不是一定意义上的运算符
fun hello (double:Double,vararg ints:Int,string:String){ ints.forEach(::println)} 使用: val array = intArrayOf(1,2,3,4) hello(3.0,*array,string="Hello") 复制代码