本篇文章是对Kotlin语言入门学习(一)的补充,适用于有一定Java基础的同学学习,在理解Kotlin的基本语法结构后,更重要的是加以实践,方便更快更好的理解Kotlin语言。
一、Kotlin是什么
Kotlin是一种基于JVM的静态类型编程语言
Kotlin的入口是main()函数
Kotlin的特点:
1,极简:语法简洁优雅,类型系统中一切皆引用
2,空安全:?可空
3,多范式:Kotlin同时支持OOP与FP编程范式
4,可扩展:Kotlin可直接扩展函数与属性
5,高阶函数与闭包
6,支持快速实现DSL
7,智能推断
Kotlin的工具平台:云端IDE,命令行REPL,IDEA
二、Kotlin语法基础
throw表达式:在Kotlin中,throw是表达式,它的类型是特殊类型Nothing。该类型没有值,与C、Java中的void意思一样
Kotlin中有两种类型的相等性:
引用相等=== !== (两个引用指向同一对象,即值与引用都相等)
结构相等== != (使用equals()判断,比较值)
Elvis操作符 ?: 在Kotlin中,Elvis操作符特定是跟null进行比较,如:y = x?:0 等价于:val y = if(x!==null) x else 0
非空断言“!!”
Kotlin提供了断言操作符“!!”,使得可空类型对象可以调用成员方法或者属性(但遇见null,就会导致空指针异常)
Kotlin中没有三元表达式,对应的是:if...else语句,如:if(true) 1 else 0。而Elvis操作符是精简版的三元运算符
三、类型系统与可空类型
3.1类型系统
相对于Java语言,Kotlin语言去掉了原始数据类型,只有包装类型
Kotlin系统类型分为可空类型和不可空类型
Kotlin在类型T后面加个“?”,就表达了可空类型
fun main(args:Array<String>){
println(strLength(null))
println(strLength("abc"))
}
fun strLength(s:String?):Int{
return s?.length ?:0 //?.是安全调用符,?:是Elvis操作符
}
3.2特殊类型
Unit、Nothing、Any及其对应的可空类型Unit?、Nothing?、Any?
当一个函数没有返回值的时候,用Unit来表示这个特征,而不是null,但大多数时候,可省略,返回类型是Unit
Void对应Nothing?,其唯一可被访问的返回值是null
如果一个函数的返回值是Nothing,意味着这个函数永远不会有返回值
Any?是可空类型层次的根,Any是非空类型层次结构的根,Any?是Any的超集,Any?是Kotlin类型层次结构的最顶端
3.3类型检测与类型转换
Kotlin中的is和!is类似于Java中的instanceOf,类型匹配
as运算符用于类型转换,as?为可空转换,如果类型不兼容,则返回null
在Kotlin中,父类是禁止转换为子类的
四、类与面向对象编程
Kotlin中没有静态属性和方法,但可以使用关键字object声明一个object单例对象,Kotlin中还提供了伴生对象,用companion object关键字声明
数据类:只存储数据,不包含操作行为的类,Kotlin中使用关键字data class可创建一个只包含数据的类,类似于Java中的bean类
五、函数与函数式编程
5.1函数式编程
函数式编程(FP),使一种编程范式,即面向函数编程,核心思想在于解决问题的过程,把任务分解为一个个的函数,最后通过函数组合来实现目标
比如,我们现在有一个字符串列表:val strList = listOf("a","ab","abc","abcd","abcde","abcdef","abcdefg")
现在我们想要过滤出字符串元素中长度是奇数的列表,那么可以把这个问题的解决逻辑拆成两个函数来组合实现:
val f = fun (x:Int) = x % 2 == 1 //判断输入的Int是否奇数
val g = fun (s:String) = s.length //返回输入的字符串参数的长度
再使用函数h来封装:
val h = fun (g:(String) -> Int,f:(Int -> Boolean):(String) -> Boolean){
return{ f(g(it)) }
}
这个h函数稍显长,可通过类型别名typealias使代码更简洁
5.2Kotlin中的特殊函数
特殊函数主要有:run()、apply()、let()、also()、with()
run():使用时可使用run(其它函数),表示执行()内的函数,()可省略
apply():通过.方式调用,表示在run()的基础上返回当前调用者对象
let():通过.方式调用,表示把当前调用对象作为参数传给let函数,如myfun().let{println(it)},则表示执行完myfun函数后,返回这传给let()函数,最后打印结果为myfun()返回值
also():通过.方式调用,表示在let()基础上返回当前调用者
with():执行传入的代码块,或者理解为接收一个指定类型的对象去执行body函数
以上5种函数没有给出具体示例,希望读者找相关例子进行更好的理解并在实践中加以应用
六、扩展函数
为List扩展一个filter()函数
fun <T> List<T>.filter(predicate: (T) -> Boolean):MutableList<T>{
val result = ArrayList<T>()
this.forEach{
if(predicate(it)){
result.add(it)
}
}
return result
}
调用:
val list = mutableListOf(1,2,3,4,5,6,7)
val result = list.filter{
it%2==1
}
predicate(result) //[1,3,5,7]
扩展属性:允许定义在类或者Kotlin文件中,不允许定义在函数中
七、集合类
集合类存放的都是对象的引用,而非对象本身,Kotlin中集合类分为:可变集合类(Mutable)与不可变集合类(Immutable)
遍历集合中的元素:forEach
list.forEach{
println(it)
}
映射函数map:
val list = listOf(1,2,3,4,5,6,7) //声明并初始化一个List
list.map{it*it} //map函数对每个元素进行乘方操作,返回[1,4,9,16,25,36,49]
set和map类似
过滤函数filter:
data class Student(var id:Long,var name:String,var age:Int,var score:Int){ //声明Student数据类
override fun toString():String{ //覆写toString()函数
return "Student(id = $id,name = '$name',age = $age,score = $score)"
}
}
创建一个持有Student对象的List
val studentList = listOf(
Student(1,"Jack",18,90),
Student(2,"Rose",17,90),
Student(3,"Alice",16,70),
)
此时,如果我们想要过滤出大于等于18岁的学生,可以这样写:
studentList.filter{it.age>=18}
输出结果:[Student(id = 1,name = "Jack",age = 18,score = 90)]
排序函数:
reversed()倒序
sorted()升序
元素去重:
distinct()
八、泛型
类型上界
fun <T:Comparable<T>> gt(x:T,y:T):Boolean //T的类型上界是Comparable<T>,即告诉编译器,类型参数T代表的都是实现了Comparable接口的类,这样等于告诉编译器,它们都实现了CompareTo方法。
如果没有上界声明,则无法直接使用CompareTo操作符
out T 等价于 ? extend T 指定类型参数的上界
in T 等价于 ? super T 指定类型参数的下界
九、文件I/O操作、正则表达式与多线程
Kotlin的序列化直接采用了Java序列化类的类型别名
internal typealias Serializable = java.io.Serializable
Kotlin中常用的文件读写API:
File.readText() //读取该文件的所有内容作为一个字符串返回
File.readLines() //读取该文件的每一行内容,存入一个List返回
File.readBytes() //读取文件所有内容以ByteArray的方式返回
File.writeText() //覆盖写入text字符串到文件中
File.writeBytes() //覆盖写入ByteArray字节流数组
File.appendText() //在文件末尾追加写入text字符串
File.appendBytes() //在文件末尾追加写入ByteArray字节流数组
9.1遍历文件树
遍历文件树:walk函数
下面的例子遍历了指定文件夹下的所有文件
fun traverseFileTree(filename:String){
val f = File(filename)
val fileTreeWalk = f.walk() //调用walk()会返回一个FileTreeWalk对象
fileTreeWalk.iterator().forEach{
println(it.absolutePath)
}
}
9.2递归复制文件
复制该文件或者递归该目录及其所有子文件到指定目录下,如果指定路径下的文件不存在,会自动创建
copyRecursively函数签名:
fun File.copyRecursively{
target:File, //目标文件
overrite:Boolean = false //是否覆盖
onError:(File,IOException) -> OnErrorAction = { _,exception -> throw exception}) //错误处理
}:Boolean
9.3网络I/0
readBytes和readText
使用这两个方法配合正则表达式实现网络爬虫功能:
根据URL获取该URL的响应HTML函数:
fun getUrlContent(url:String):String{
return URL(url).readText(Charset.defaultCharset()) //获取该URL的响应HTML文本
}
根据URL获取该URL的响应比特数组函数
fun getUrlBytes(url:String):ByteArray{
return URL(url).readBytes //获取该URL的响应ByteArray
}
把URL响应字节数组写入文件中
fun writeUrlBytesTo(filename:String,url:String){
val bytes = URL(url).readBytes()
File(filename).writeBytes(bytes) //写入文件
}
9.4正则表达式
构造Regex表达式
val r1 = Regex("[a-z]+") //创建一个Regex对象,匹配的正则表达式是[a-z]+
val r2 = "[a-z]+".toRegex() //直接使用Kotlin中给String扩展的toRegex函数
Regex函数:
mataces() //输入字符串全部匹配
containMatchIn() //输入字符串至少有一个匹配
matchEntrie() //输入字符串全部匹配,返回一个匹配结果对象
replace() //把输入字符串中匹配的部分替换成replacement的内容//把输入字符串中匹配到的值,用函数transform映射之后的新值替换
find() //返回输入字符串中第一个匹配的值
findAll() //返回输入字符串中所有匹配的值MatchResult的序列
同步方法和块:
synchronized不是Kotlin中的关键字,它替换为@Sychronized注解
同样的,Kotlin中没有volalile关键字,但是有@Volatile注解
参考:《Kotlin从入门到进阶实战》 ——陈光剑