语法层面
- 可空对象(和 C# 的
<Nullable>enabled</Nullable>
相似)Int
和Int?
是两种不同的类型;String
和String?
也是两种不同的类型(前者是后者的子类型)
var a: Int = 0;
var b: Int? = 0;
a = b; // ⇐ 不能将 Int? 赋值给 Int
b = a;
- 不可变类型/可变类型
val
声明不可变变量,不可再赋值;var
声明可变变量,能再赋值。
var a = 0;
val b = 1;
a = b;
b = a; // ⇐ 不能对 val 变量赋值
- 字符串插值
val PI = 3.1415926
val s1 = "PI is ${PI}"; // PI is 3.1415926
val s2 = "PI is ${String.format("%.2f", PI)}"; // PI is 3.14
字符串插值语法不支持设置格式(这点不如 C# 方便)
- 对函数式编程的支持,一切都是表达式
没有条件(三目)运算符,因为if
分支就能做到(只是写起来字多一点)
fun fixInt(value: Int?): Int {
val n = value ?: 0;
return if (n >= 0) n else -n;
// C# 的 int? 可以参与运算,这点不同
}
when
甚至 try ... catch
都可以作为表达式
fun devide(m: Int, n: Int) {
return try {
m / n
} catch (e: ArithmeticException) {
0
}
}
- 函数式编程支持:
with
、also
、let
、run
、apply
上面的fixInt
可以用let
来改写,注意是?.let
表示let
块里的it
是不含空的类型
fun fixInt(value: Int?): Int {
return value?.let { if (it >= 0) it else -it } ?: 0
}
with(obj)
块中会把 this
引用到 obj
对象上去,而 this.
在不冲突的情况下是可以省略的
with ("Hello World") {
println("`${this}` has ${length} characters")
}
// `Hello World` has 11 characters
let
、also
、run
、apply
都是通过点号 (.
) 调用,前两个引入 it
(或自定义变量),后两个引入 this
;also
和 apply
返回调用者,其他的返回最后一行的计算结果。
- 属性(去 getter/setter)
- 扩展方法
fun String.blabla() { ... }
感觉比 C# 的更合理,但是不能作为静态函数调用(虽然本质就是静态函数)
- 无差别的 Lambda(想想
Consumer
,Runable
等,相同签名但不同接口的 Lambda 不能互换) - 对象解构
operator fun componentN()
操作符方法,用于解构。N
从 1 开始,按顺序递增。 - when 分支(Java 12 有 switch 表达式)
when (view) {
is TextView -> toast(view.text)
is RecyclerView -> toast("Item count = ${view.adapter.itemCount}")
is SearchView -> toast("Current query: ${view.query}")
else -> toast("View type not supported")
}
工具(案例演示)
- 返转一个数组
int[]
- 字符串工具函数,比如
padStart
, orEmpty
等 - 类似 stream,但更简洁,
forEachIndexed
- 快速创建 List 和 Map
- 把一大断
byte[]
转成十六进制并按每行 16 个字节的格式输出(文本)
其他
- 协程和
await