Kotlin语法笔记

Since 2019/10/12

变量和函数

变量

  1. val a: Int = 10 // 声明常量
  2. var b = 6.99 // 声明变量
Java Kotlin 说明
int Int 整型
long Long 长整型
short Short 短整型
float Float 单精度
double Double 双精度
boolean Boolean 布尔型
char Char 字符型
byte Byte 字节型

函数

1
2
3
fun myIntMax(p1: Int, p2: Int): Int {
return max(p1, p2)
}

单表达式化简->

1
fun myIntMax(p1: Int, p2: Int): Int = max(p1, p2)

类型推导化简->

1
fun myIntMax(p1: Int, p2: Int) = max(p1, p2)

逻辑控制

if

用 if 实现max()

1
2
3
4
5
6
7
8
9
fun myIntMax(p1: Int, p2: Int): Int {
var value = 0
if (p1 > p2) {
value = p1
} else {
value = p2
}
return value
}

利用 if 的返回值->

1
2
3
4
5
return if (p1 > p2) {
p1
} else {
p2
}

单表达式化简->

1
fun myIntMax(p1: Int, p2: Int) = if (p1 > p2) p1 else p2

when

带参数的 when,参数类型没有限制

1
2
3
4
5
fun getScore(name: String) = when (name) {
"Tom" -> 86
"Jim" -> 77
else -> 0
}

还可以按类型选择

1
2
3
4
5
6
7
fun checkNumber(num: Number) { // Number 是数字数据类型的父类
when (num) {
is Int -> println("num is Int")
is Double -> println("num is Double")
else -> println("number not support")
}
}

不带参数的 when,更加灵活

1
2
3
4
5
6
fun getScore(name: String) = when {
name.startWith("Tom") -> 86
name == "Jim" -> 77 // 不需要显式equals()
name == "Jack" -> 95
else -> 0
}

while

和 Java 相同。

for

取消了 for-i 循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
val range = 0..10 // 创建一个左闭右闭区间

fun main() {
for (i in 0..10) { // 左闭右闭区间
println(i)
}

for (i in 0 until 10 step 2) { // 左闭右开区间
println(i)
}

for (i in 10 downTo 1 step 3) { // 左闭右闭降序

}
}

面向对象

类与对象

1
2
3
4
5
6
7
8
9
10
11
class Person { // 默认public,且不可继承
var name = "" // 默认public

fun eat() {
println(name + " is eating.")
}
}

fun main() {
val p = Person() // 不需要new
}

继承与构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
open class Person { // open,允许继承
}

// 主构造函数
class Student(val sno: String, val grage: Int): Person(/*调用父构造函数*/) {
// sno, grage自动成为类成员
// 如果不想自动成为类成员,则不要加val或var修饰符
/* 向主构造函数加逻辑
init {
println("sno is " + sno)
}
*/

// 此构造函数
constructor(name: String, age: Int): this("dzf", 100) {
}

}

// 仅有次构造函数
// 则声明处不需要声明调用父构造函数了
class Stu: Person {
// 没有了主构造函数,这里就不能this(),只能super()
constructor(name: String, age: Int): super() {
}
}

接口

1
2
3
4
5
6
7
8
9
10
11
12
interface Study {
fun readBooks() // 可以不实现
fun doHomework() {
// 也可以提供默认实现
}
}

class Stu(): Person(), Study {
override fun readBooks() { // 覆盖实现
println("reading.")
}
}

可见性

修饰符 Java Kotlin
public 所有类可见 所有类可见(默认)
private 当前类可见 当前类可见
protected 当前类、子类、同一包下的类可见 当前类、子类可见
default 同一包下的类可见
internal 同一模块下的类可见

数据类

类修饰符data,自动生成各种方法:

1
2
3
4
data class Cellphone(val brand:String, val number:Int) // 没有代码,省略大括号
public override Boolean equals(Object)
public override Int hashCode()
public override String toString()

单例类

类修饰符object,使类名成为全局唯一对象

1
2
3
4
5
6
object Singleton { // 注意没有class
fun test() {
}
}

Singleton.test() // 调用

伴生单例

包裹在 companion object {} 内部即可。性质类似静态成员。

1
2
3
4
5
6
7
8
class Util {
companion object {
// @JvmStatic
fun factory(): Util {

}
}
}

真正的静态成员

在伴生单例内加入 @JvmStatic 注解,或者,顶层方法是静态成员方法。

在 Java 中,将 kt 的文件名看作类名,即可调用 kotlin 顶层方法。

Lambda编程

集合

列表

1
2
3
4
5
6
7
8
9
val list = ArrayList<String>() // 可变
list.add("Apple")
list.add("Banana")
// -------------------------------
val list = listOf("Apple", "Banana") // 不可变
val list2 = mutableListOf("Apple", "Banana") // 可变
for (fruit in list) {
println(fruit)
}

集合

1
val set = setOf("Apple", "Banana") // HashSet

Map

1
2
3
4
5
6
7
8
val map = HashMap<String, Int>()
map.put("Apple", 1)
map["Banana"] = 1
// --------------------------------
val map = mapOf("Apple" to 1, "Banana" to 2) // to 是 infix函数
for ((fruit, number) in map) {
println(fruit + " is " + number)
}

集合的函数式API

1
2
3
4
val maxLengthFruit: String = list.maxBy{ it.length }
val newList = list.filter{ it.length < 5 }.map { it.toUpperCase() }
val isOk: Boolean = newList.all{ it.length < 5 }
val isFault: Boolean = newList.any{ it.length >= 5 }

Lambda表达式语法结构:

1
2
{v1: Type, v2: Type -> body}
// 返回值是body的最后一行代码

Lambda表达式举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
val lambda = { fruit: String -> fruit.length }
val maxLengthFruit = list.maxBy(lambda)
val maxLengthFruit = list.maxBy({ fruit: String -> fruit.length })

// lambda是最后一个参数
val maxLengthFruit = list.maxBy(){ fruit: String -> fruit.length }

// lambda是唯一一个参数
val maxLengthFruit = list.maxBy{ fruit: String -> fruit.length }

// 自动推导参数类型
val maxLengthFruit = list.maxBy{ fruit -> fruit.length }

// lambda内只有一个参数
val maxLengthFruit = list.maxBy{ it.length }

Java函数式API

Java单抽象方法接口(例如Runnable)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Thread(object : Runnable { // object 关键字,代表一个匿名对象
override fun run() {
println("Thread is running.")
}
}).start()

// Runnable只有一个抽象方法
Thread(Runnale {
println("Thread is running.") // Lambda表达式覆盖run()
}).start()

//

// Thread的参数列表中有且只有Runnable
Thread({
println("Thread is running.") // Lambda表达式覆盖run()
}).start()

// lambda是唯一一个参数
Thread {
println("Thread is running.")
}.start()

// 举例
button.setOnClickListener {
}

常用标准函数

  1. let 返回最后一行
    1
    2
    3
    obj?.let {
    it.f()
    }
  2. also 返回本身
    1
    2
    3
    obj?.also {
    it.f()
    }
  3. with 返回最后一行
    1
    2
    3
    4
    with(StringBuilder()) {
    append("\n")
    toString()
    }
  4. run 返回最后一行
    1
    2
    3
    4
    StringBuilder().run {
    append("\n")
    toString()
    }
  5. apply 返回本身
    1
    2
    3
    StringBuilder().apply {
    append("\n")
    }

空类型系统

Kotlin默认编译器形参不可为空。

可空类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fun doStudy(a: Study?, b: Study) { // 加问号,表示可空
a.readBooks() // 编译错误,未处理空
a?.readBooks() // 正确,若a为null则返回null
a!!.readBooks() // 正确,向编译器保证a不为空。
val c = a ?: b // c = if (a!=null) a else b
}

fun getTextLength(text: String?) = text?.length ?: 0

fun doStudy(a: Study?) { // 简化版
a?.let { // 内置的let函数
it.readBooks()
it.doHomework()
}
}

let函数的优势是暂存了对象引用,不怕全局变量被多线程修改。相反,用if无法保证全局变量的非空。

字符串内嵌表达式

1
2
"Hello, ${obj.name}. Nice to meet you." // 表达式
"Hello, $name. Nice to meet you" // 变量

绑定参数

通过绑定形参-实参,可以调换参数顺序

1
myfun(str = "abc", num = 123)