变量类型和常量
数据类型
声明变量
var x: Int = 10
只读变量
val x: String = "lorem"
编译时常量
const val MAX_SIZE = 100;
Kotlin只提供引用数据类型
逻辑控制语句
条件语句
if (age >= 18) {
permit = true
} else {
permit = false
}
when条件语句
val aType = "A"
val theType = when (aType) {
"A" -> "Got Type A"
"B" -> "Got Type B"
else -> "Not a validate Type"
}
循环语句
range(..操作符)
val x = 10
val isInRange = x in 0..20
for语句
for (item in itemList) {
//TODO
}
while语句
while (cond) {
//TODO
}
字符串,列表、集合和映射
字符串
字符串模板
val hello = "Hello"
val world = "World"
val s = "$hello $world"
字符串比较
就比较字符串来说,操作符的行为方式和 Kotlin 不 一样,Java 用做引用比较。要在 Java 中做结构相等比较,要用 equals 函数。做引用相等判断时使用符号。
列表
只读列表
// 创建
val itemList: List<String> = listOf("A, "B", "C")
// 添加
itemList.add("D")
// 获取元素
val item0 = itemList[0];
val itemOrDefault = itemList.getOrElse("Default")
val itemOrNull = itemList.getOrNull()
val itemFirst = itemList.first();
val itemLast = itemList.last();
// 修改删除
itemList.remove("B")
可变列表
val itemList: List<String> = mutableListOf("A, "B", "C")
itemList[0] = "AA"
遍历
for (item in itemList) {...}
List::forEach
List::forEachIndexed
解构(componentN()函数)
val (x, y, z) = listOf(1.1, 2.2, 3.3)
集合
val userIDSet = setOf(1, 2, 3)
val isContains = userIdSet.contains(2)
映射
使用
val map: Map<String, Double> = mutableMapOf("Math" to 88.5, Pair("English", 92.0))
val mathScore = map["Math"] // Map::getValue Map::getOrElse Map::getOrDefault
map["Math"] = 90.0
函数
函数定义
public fun add(a: Int, b: Int): Int {
<return> a + b
}
尾递归函数
tailrec fun fact(n: Int, acc: Int = 1) {
if (n == 0 || n == 1) return acc
return fact(n - 1, n * acc)
}
## 默认值参数
```kotlin
public fun plus(a: Int, b: Int = 1): Int {
a + b
}
单表达式函数
public fun add(a: Int, b: Int)<: Int> = a + b
具名函数参数
val result = add(a=3, b=4)
匿名函数
定义
val add:(Int, Int) -> Int = {a: Int, b: Int ->
a + b
}
it关键字
val print: (String) -> Unit = { println(it) }
简略语法
// 如果一个函数的 lambda 参数排在最后,那么括住 lambda 值参的一对圆 括号就可以省略。
"hello world".count { it == 'o' }
异常
null类型
val s: String? = null
安全调用操作符
s?.capitalize() // 如果遇到 null 值,它就跳过函数调用
非空断言操作符
s!!.capitalize() // 如果遇到 null 值,立刻抛出空指针异常
空合并操作符
val s: String = aStringOrNull ?: "Default"
抛出异常
throw IlleagalStateException("...")
自定义异常
class MyException(): IlleagalStateException("...")
处理异常
try {
val result = 1/0
} catch (e: Exception) {
//TODO
}
先决条件函数
通用工具类标准函数
apply应用函数
。apply 函数可看作一个配置函数:你可以传入一个接收者, 然后调用一系列函数来配置它以便使用。如果提供 lambda 给 apply 函数执行,它会返回配置好 的接收者。
相关作用域(relative scoping) lambda 表达式里的所有函数调用 都是针对接收者的。
let映射值
let 函数可以用于任何类型的接收者,调用后会返回 lambda 表达式的求值结果。
run函数
run 有作用域行为,函数不返回接收者,可返回值
with函数
with 函数是 run 的变体。它们的功能行为是一样的,但 with 的调用方式不同。和之前介绍 的标准函数都不一样,调用 with 时需要值参作为其第一个参数传入。
also函数
also 函数和 let 函数功能相似。和 let 一样,also 也是把接收者作为值参传给 lambda。但 有一点不同:also 返回接收者对象,可以基于原始接收者对象执行额外的链式调用。
takeIf函数
takeIf 函数。和其他标准函数有点不一样,takeIf 函数需要判断 lambda 中提供的条件表达式(叫 predicate),给出 true 或 false 结果。如果判断结果是 true,从 takeIf 函数返回接收者对象;如果是 false,则返回 null。
apply also 返回接收者对象 run let 返回lambda结果
类
定义
class Person{
val name: String
publci fun run () {
println("Person::run")
}
}
getter和setter
class Foo {
var name: String
get() = field.capitalize()
set(value) {
field = value.trim()
}
}
主构造函数
class Person(_name: String)
主构造函数中定义属性
class Person(val name: String)
次构造函数
calss Person(val name: String, val level: Int) {
constructor(name: String): this(name, 1)
}
默认参数 命名参数
初始化块
class Person(val age: Int) {
init{
require(age > 0, { "age must greater than zero" })
}
}
初始化顺序
延迟初始化
实际上,使用 lateinit 关键 字就相当于你和自己做了个约定:我会在用它之前负责初始化的。
class Person{
lateinit var name: String
fun initMenually(_name: String) {
name = _name_
}
}
惰性初始化
惰性初始化在 Kotlin 里是使用一种叫代理的机制来实现的。代理负责约定属性该如何初始化。 属性直到首次被引用时才会被初始化。到那时,lazy 的 lambda 表达式中 的所有代码都会被执行一次且只会执行一次。
class Person{
val name: String by lazy { "the name" }
}
继承
,类默认都是封闭的,也就是说不允许其 他类来继承自己。要让某个类开放继承,必须使用 open 关键字修饰它。
class Student: Person("default name")
操作符左边的类名和其右边的构造函数调用。
父类的 load 函数也要先以 open 关键字修饰,然后子类才能覆盖它。 使用 override 关键字覆盖函数。 函数默认都是 final 的
多态
类型检测
val stu = Student()
val isStu = std is Person
Any超类
类型转换(as操作符)
(student as Person).run()
类型智能推测
对象
对象声明 object declaration
引用对象声明需要访问它的属性或函数。为触发对象的初始化 对象声明能自动实例化生成对象,所以你无须自定义构造函数来执行初始化任务
object Game {
init {
println("Game init block")
}
}
对象表达式 object expression
如果定义在独立文件里,对象表达式会立即初始化; 如果定义在另一个类里,那么只有包含它的类初始化时,对象表达式才会被初始化。
匿名类
button.OnClick(object: OnClickListener(){...})
伴生对象 companion object
一个类里只能有一个伴生对象。
伴生对象初始化也分两种情况。 第一种,包含伴生对象的类初始化时,伴生对象就会被初始化。由于这种相伴关系,伴生对象就适合用来存放和类定义有上下文关系的单例数据。 第二种, 只要直接访问伴生对象的某个属性或函数,就会触发伴生对象的初始化。
class Person{
companion object{
val instance = Holder.holder
}
private object Holder {
val holder = Person()
}
}
数据对象
- toString方法
- equals方法
- copy方法
- 自动添加componentN方法,使得可以使用解构声明语法
数据类必须有至少带一个参数的主构造函数; 数据类主构造函数的参数必须是 val 或 var; 数据类不能使用 abstract、open、sealed 和 inner 修饰符。
data class Person(val name: String, val age: Int)
枚举类
enum class Direction{
NORTH,
EAST,
WEST,
SOUTH
}
enum class Direction(private val coordinate: Coordinate) {
NORTH(Coordinate(0, -1)),
EAST(Coordinate(1, 0)),
SOUTH(Coordinate(0, 1)),
WEST(Coordinate(-1, 0))
}
enum class Direction(private val coordinate: Coordinate) {
NORTH(Coordinate(0, -1)),
EAST(Coordinate(1, 0)),
SOUTH(Coordinate(0, 1)),
WEST(Coordinate(-1, 0));
fun updateCoordinate(playerCoordinate: Coordinate) =
Coordinate(playerCoordinate.x + coordinate.x,
playerCoordinate.y + coordinate.y)
}
运算符重载
data class Coordinate(val x: Int, val y: Int) {
val isInBounds = x >= 0 && y >= 0
operator fun plus(other: Coordinate) = Coordinate(x + other.x, y + other.y)
}
接口
定义接口
interface Fightable {
var healthPoints: Int
val diceCount: Int
val diceSides: Int
val damageRoll: Int
fun attack(opponent: Fightable): Int
}
kotlin接口可以约定属性
实现接口
class Player(_name: String,
override var healthPoints: Int = 100,
var isBlessed: Boolean = false,
private var isImmortal: Boolean) : Fightable { ... }
接口默认实现
interface Fightable {
var healthPoints: Int
val diceCount: Int
val diceSides: Int
val damageRoll: Int
get() = (0 until diceCount).map {
Random().nextInt(diceSides) + 1
}.sum()
fun attack(opponent: Fightable): Int
}
抽象类
abstract class Monster(val name: String,
val description: String,
override var healthPoints: Int) : Fightable {
override fun attack(opponent: Fightable): Int {
val damageDealt = damageRoll opponent.healthPoints -= damageDealt
return damageDealt
}
}
泛型
PECS/out,in/协变逆变
vararg关键字
reified保留泛型信息
扩展
扩展函数
fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount)
泛型扩展函数
fun T.easyPrint(): T { println(this) return this }
扩展属性
val String.numVowels get() = count { "aeiouy".contains(it) }
infix关键字
infix 关键字适用于有单个参数的扩展和类函数,可以让你以更简洁的语法调用函数。如果 一个函数定义使用了 infix 关键字,那么调用它时,接收者和函数之间的点操作符以及参数的 一对括号都可以不要。
重命名扩展
import com.bignerdranch.nyethack.extensions.random as randomizer