本章节主要介绍Kotlin自带的一些表达式和简单使用
20211117161347

常量和变量

变量

Java

1
2
int a = 2;
a = 3;

Kotlin

1
2
var a = 2
a = 3

只读变量

Java

1
final int b = 3;

Kotlin

1
val b = 3

常量

Java

1
static final int b = 3;

Kotlin

  • 只能定义在全局范围
  • 只能修饰基本类型
  • 必须立即用字面量初始化
    1
    const val b = 3

编译期和运行时常量

1
2
3
const val b = 3 // 编译期即可确定常量的值,并用值替换调用处
val c: Int
运行时才能确定值,调用处通过引用获取值

表达式

if … else

Java

Java支持三目运算符,所以可以使用以下语法

1
c = a == 3 ? 4 : 5;

Kotlin

Kotlin中,if ... else ...也属于表达式,所以Kotlin开发者没有提供三目运算符,直接使用if ... else ...可以达到相同的效果

1
c = if(a == 3) 4 else 5

when …

Java

1
2
3
4
5
switch(a) {
case 0: c = 5; break;
case 1: c = 100; break;
default: c = 20;
}

Kotlin

1
2
3
4
5
when(a) {
0 -> c = 5
1 -> c = 100
else -> c = 20
}

在Java里,switch表达式只支持byte、short、int、char、String或者枚举,但是Kotlin中,相当于Scala的模式匹配,支持的语句相当丰富,比如下面的也是可以的

1
2
3
4
5
when(person) {
is Male -> println("${person.name} 是男人")
is FeMale -> println("${person.name} 是女人")
else -> println("${person.name} emm...")
}

条件可以转移到分支

1
2
3
4
5
6
var x: Any = ...
when {
x is String -> c = x.length
x == 1 -> c = 100
else -> c = 20
}

由于Kotlin里面,when是一个表达式,所以允许有值返回,上述也可以写成下面这样

1
2
3
4
5
c = when {
x is String -> x.length
x == 1 -> 100
else -> 20
}

try … catch …

Java

1
2
3
4
5
6
try {
c = a / b;
} catch(Exception e) {
e.printStackTrace();
c = 0;
}

Kotlin

1
2
3
4
5
6
c = try {
a / b
} catch(e: Exception) {
e.printStackTrace()
0
}

运算符与中缀表达式

运算符

  • Kotlin支持运算符重载
  • 运算符的范围仅限官方指定的符号

    一元操作

    一元前缀操作符

    表达式 翻译为
    +a a.unaryPlus()
    -a a.unaryMinus()
    !a a.not()

当编译器处理例如表达式 +a 时,它执行以下步骤:

  1. 确定a的类型,令其为T
  2. 为接收者T查找一个带有operator修饰符的无参函数unaryPlus(),即成员函数或扩展函数;
  3. 如果函数不存在或不明确,则导致编译错误;
  4. 如果函数存在且其返回类型为R,那就表达式+a具有类型R

注意:这些操作以及所有其他操作都针对基本类型做了优化,不会为它们引入函数调用的开销。

以下是如何重载一元减运算符的示例

1
2
3
4
5
6
7
8
9
data class Point(val x: Int, val y: Int)

operator fun Point.unaryMinus() = Point(-x, -y)

val point = Point(10, 20)

fun main() {
println(-point) // 输出“Point(x=-10, y=-20)”
}

递增与递减

表达式 翻译为
a++ a.inc()
a– a.dec()

二元操作

算术运算符

表达式 翻译为
a + b a.plus(b)
a - b a.minus(b)
a * b a.times(b)
a / b a.div(b)
a % b a.rem(b) 或者 a.mod(b) 已弃用
a..b a.rangeTo(b)

下面是一个从给定值起始的Counter类的示例,它可以使用重载的+运算符来增加计数

1
2
3
4
5
data class Counter(val dayIndex: Int) {
operator fun plus(increment: Int): Counter {
return Counter(dayIndex + increment)
}
}

In操作符

表达式 翻译为
a in b b.contains(a)
a !in b !b.contains(a)

索引访问操作符

表达式 翻译为
a[i] a.get(i)
a[i, j] a.get(i, j)
a[i_1, ……, i_n] a.get(i_1, ……, i_n)
a[i] = b a.set(i, b)
a[i, j] = b a.set(i, j, b)
a[i_1, ……, i_n] = b a.set(i_1, ……, i_n, b)

调用操作符

表达式 翻译为
a() a.invoke()
a(i) a.invoke(i)
a(i, j) a.invoke(i, j)
a(i_1, ……, i_n) a.invoke(i_1, ……, i_n)

广义赋值

表达式 翻译为
a += b a.plusAssign(b)
a -= b a.minusAssign(b)
a *= b a.timesAssign(b)
a /= b a.divAssign(b)
a %= b a.remAssign(b), a.modAssign(b)(已弃用)

相等与不等操作符

表达式 翻译为
a == b a?.equals(b) ?: (b === null)
a != b !(a?.equals(b) ?: (b === null))

比较操作符

所有的比较都转换为对compareTo的调用,这个函数需要返回Int

表达式 翻译为
a > b a.compareTo(b) > 0
a < b a.compareTo(b) < 0
a >= b a.compareTo(b) >= 0
a <= b a.compareTo(b) <= 0

属性委托操作符

中缀表达式(infix)

前面章节提到过,初始化Map时,可以使用mapOf(1 to 2),这里的x to y就是中缀表达式,这个函数表现为

1
infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, thar) // 加infix关键字

Lambda表达式

匿名函数的类型,类型与普通函数一致

1
2
3
val func: () -> Unit = fun() {
println("Hello")
}

Lambda表达式的定义

无参数无返回值
Java(since 1.8)

1
2
3
Runnable lambda = () -> {
System.out.println("Hello");
}

Kotlin

1
2
3
val lambda = {
println("Hello")
}

有参数无返回值
Java(since 1.8)

1
2
3
4
5
6
7
interface Function1 {
void invoke(int p);
}

Function1 f1 = (p) -> {
System.out.println(p);
}

Kotlin

1
val f1: (Int) -> Unit = { p: Int -> println(p) }

还可以简写为

1
val f1: (Int) -> Unit = { println(it) } // 默认的匿名函数参数名称为`it`