1. 函数语法糖
一行,则简化之。返回类型也可以省略。
fun findMax(num1: Int, num2: Int) = max(num1, num2)
2. if 可以有返回值
返回值是每一个条件中最后一行代码的返回值。
fun findMax2(num1: Int, num2: Int): Int {
val value = if (num1 > num2) {
num1
} else {
num2
}
return value
}
进而可以简化成:
fun findMax3(num1: Int, num2: Int) = if (num1 > num2) num1 else num2
3. 条件编译 when
fun getScore(name: String) = when (name) {
"qer" -> 100
"yqy" -> 105
"lby" -> 100
else -> 0
}
fun getScore2(name: String) = when {
name == "qer" -> 100
name == "yqy" -> 105
name == "lby" -> 100
name.startsWith("Tom") -> 1000 // 所有Tom开头的
else -> 0
}
4. for循环
var range = 0..10 // [0,10]
var range2 = 0 until 10 // [0,10)
var range3 = 10 downTo 1 // [10,1]
for (i in range step 2) { // i += 2
print(i)
}
5. 构造函数
5.1 主构造函数
Person.kt
open class Person(val name: String, val age: Int) {
fun eat() {
println(name + "is eating. He/She is " + age + " years old.");
}
}
Student.kt
class Student(val sno: String, val grade: Int, name: String, age: Int) :
Person(name, age) {
}
子类中的构造函数必须调用父类中的构造函数
在主构造函数中声明成val或者var的参数将自动成为该类的字段
在默认主构造函数的时候,Person后面是空的,Student继承的时候Person后面要跟括号,就是因为Student类的主构造函数在初始化的时候会调用Person类的无参数构造函数。
5.2 次构造函数
当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用)。
class Student(val sno: String, val grade: Int, name: String, age: Int) :
Person(name, age) {
constructor(name: String, age: Int) : this("", 0, name, age) {
}
constructor() : this("", 0);
}
类中只有次构造函数,没有主构造函数的情况:
class Student : Person {
constructor(name: String, age: Int) : super(name, age) {
}
constructor() : this("", 0);
}
因为没有主构造函数,所以Person后面没有加括号
this关键字换成super好像是java中的特性
6. 接口
Student.kt
class Student(name: String, age: Int) : Person(name, age), Study {
override fun readBooks() {
println(name + " is reading.")
}
}
fun main() {
val student = Student("qer", 10)
doStudy(student)
}
fun doStudy(study: Study) {
study.readBooks()
study.doHomework()
}
Study.kt
interface Study {
fun readBooks()
fun doHomework() {
println("this is default implementation of doHomework()")
}
}
doStudy() 函数接收一个Study类型的参数,由于Student类实现了Study接口,因此Student类的实例是可以传递给doStudy()函数的。
java和kotlin可见性修饰符的异同:
7. 数据类和单例类
7.1 数据类
data class Cellphone(val brand: String, val price: Double)
/qiang
7.2 单例类
fun main() {
Singleton.singletonTest()
}
object Singleton {
fun singletonTest() {
println("singletonTest is called.")
}
}
8. Lambda
8.1 集合的创建与遍历
set 集合底层是使用hash映射机制来存放数据的,因此集合中的元素无法保证有序。
map初始化中的to并不是关键字,而是一个infix函数。
val list = listOf("qer1", "qer2", "qer3")
val list2 = mutableListOf("qer1", "qer2", "qer3") // 这里用val 或者 var好像并没有什么影响,但是会被推荐使用 val
list2.add("qer4")
val set = setOf("qer1", "qer2", "qer3")
val set2 = mutableSetOf("qer1", "qer2", "qer3")
set2.add("qer4")
for (per in set2) {
println(per)
}
val map = mapOf<String, Int>("qer1" to 1, "qer2" to 2, "qer3" to 3)
val map2 = mutableMapOf<String, Int>("qer1" to 1, "qer2" to 2, "qer3" to 3)
map2["qer4"] = 4
map2["qer5"] = 5
for ((per, num) in map2) {
println("${per} 's num is ${num}")
}
8.2 集合的函数式API
maxby
Lambda表达式的语法结构:
{ 参数名1: 参数类型, 参数名2: 参数类型 -> 函数体 }
val list3 = listOf("qer1", "qer11111", "qer111")
val maxQer0 = list3.maxBy({ qers: String -> qers.length }) // 持续化简变成下一行
val maxQer = list3.maxBy { it.length }
println(maxQer0)
几个化简的原则:
- 当Lambda把参数是函数的最后一个参数时,可以将Lambda表达式移到函数括号的外面
- 如果Lambda参数是函数的唯一一个参数的话,还可以将函数的括号省略
- Kotlin有出色的类型推导机制,Lambda表达式中的参数列表在大多数情况下不必声明参数类型
- 当Lambda表达式的参数列表中只有一个参数时,也不必声明参数名,而是可以使用it关键字来代替
map
val newList = list3.map { it.toUpperCase() }
for (per in newList) {
println(per)
}
filter
val newFilterList = list3.filter { it.length <= 6 }
.map { it.toUpperCase(Locale.ROOT) }
for (per in newFilterList) {
println(per)
}
any & all
any:用于判断集合中是否至少存在一个元素满足指定条件
all:用于判断集合中是否所有元素都满足指定条件
val anyResult = list3.any{ it.length <= 4 }
val allResult = list3.all{ it.length <= 4 }
println("${anyResult} ${allResult}")
8.3 JAVA 函数式 API 的使用
限制条件:如果我们在 Kotlin 代码中调用了一个 Java 方法,并且该方法接收一个JAVA单抽象方法接口函数,就可以使用函数式API。Java单抽象方法接口指的是接口中只有一个待实现方法,如果接口中有多个待实现方法,则无法使用函数式 API。
Thread( object : Runnable {
override fun run() {
println("Thread is running...")
}
}).start()
Thread{
println("Thread2 is running...")
}.start()
9. 关于空指针
9.1 处理空指针
kotlin默认所有的参数和变量都不可为空
Kotlin将空指针异常的检查提前到了编译时期
可空的类型系统:类名后面加上一个问号。
?.
:当对象不为空时正常调用相应的方法,当对象为空时则什么都不做
?:
:这个操作符左右两边都接受一个表达式,如果左边表达式的结果不为空就返回左边表达式的结果,否则就返回右边表达式的结果。
!!.
:非空断言,想要强行通过编译
fun main() {
val text: String? = null
var x = getTextLength(text)
println(x)
}
fun getTextLength(text: String?) = text?.length ?: 0
当text为空时,text?.lenght
会返回一个null值,这时我们再借助?:操作符让它返回0。
9.2 let
let可以使自己调用自己,可以代替那种大大的if
fun doStudy2(study: Study?) {
study?.let {
it.doHomework()
it.readBooks()
}
}