Kotlin第一天:基本语法
本着上去就是干的原则,学习kotlin第一天,看了一些基本语法;有点java基础知识的应该没有太多问题
定义函数
fun sum(a: Int, b: Int): Int {
return a + b
}
定义一个含有两个Int入参,返回值为Int的函数
和java不同点:
1、形参类型写在参数名后面,基本类型都是对象,必须大写
2、返会类型写在函数末尾
3、fun 关键字开头
4、将表达式作为函数体、返回值类型自动推断的函数:
fun sum(a: Int, b: Int) = a + b
5、函数返回无意义的值:
fun printSum(a: Int, b: Int): Unit {
println("sum of $a and $b is ${a + b}")
}
Unit相当于java中Void
无意义返回值可以省略
fun printSum(a: Int, b: Int) {
println("sum of $a and $b is ${a + b}")
}
定义变量
定义的变量前都需要加val或var,val定义只读变量,var定义可读可写的变量
val a: Int = 1 // 立即赋值
val b = 2 // 自动推断出 `Int` 类型
val c: Int // 如果没有初始值类型不能省略
c = 3 // 明确赋值
var 变量可以重新赋值
var x = 5 // 自动推断出 `Int` 类型
x += 1
字符串模板
相比java的字符串模板,kotlin强大了很多,不需要区分整形字符串等类型,字符串可以包含模板表达式 ,即一些小段代码,会求值并把结果合并到字符串中。 模板表达式以美元符($)开头,由一个简单的名字构成:
简单的值替换
val i = 10
println("i = $i") // 输出“i = 10”
包含表达式
val s = "abc"
println("$s.length is ${s.length}") // 输出“abc.length is 3”
对于要加入$符号,不支持反斜杠
val price = """
${'$'}9.99
"""
空安全
空安全编译检测
在 Kotlin 中,类型系统区分一个引用可以容纳 null (可空引用)还是不能容纳(非空引用)。
var a: String = "abc"//a 非空引用
a = null // 编译错误
var b: String? = "abc"//可空引用
b = null // ok
print(b)
如果使用a和b变量
val l = a.length//ok
val l = b.length // 错误:变量“b”可能为空
如果我们要是使用可空引用,我们该如何做呢?
条件中检测null
显示的检测b是不是null
val l = if (b != null) b.length else -1
允许在if内调用b,但是前提是这只适用于 b 是不可变的情况(即在检查和使用之间没有修改过的局部变量 ,或者不可覆盖并且有幕后字段的 val 成员),因为否则可能会发生在检查之后 b 又变为 null 的情况。
if (b != null && b.length > 0) {
print("String of length ${b.length}")
} else {
print("Empty string")
}
安全调用
你的第二个选择是安全调用操作符,写作 ?.
val a = "Kotlin"
val b: String? = null
println(b?.length)
println(a?.length) // 无需安全调用
个人觉得最大的好处是可以链式调用
bob?.department?.head?.name
如果要只对非空值执行某个操作,安全调用操作符可以与 let 一起使用:
val listWithNulls: List<String?> = listOf("Kotlin", null)
for (item in listWithNulls) {
item?.let { println(it) } // 输出 A 并忽略 null
}
还可以出现在左侧,只要任意一个环节为null,直接会跳过赋值,右侧表达式不会求值
// 如果 `person` 或者 `person.department` 其中之一为空,都不会调用该函数:
person?.department?.head = managersPool.getManager()
Elvis 操作符
elvis操作符 ?:
含义:当我们有一个可空的引用 r 时,我们可以说“如果 r 非空,我使用它;否则使用某个非空的值 x”:
val l: Int = if (b != null) b.length else -1
//等价于
val l = b?.length ?: -1
如果 ?: 左侧表达式非空,elvis 操作符就返回其左侧表达式,否则返回右侧表达式。 请注意,当且仅当左侧为空时,才会对右侧表达式求值。
请注意,因为 throw 和 return 在 Kotlin 中都是表达式,所以它们也可以用在 elvis 操作符右侧。这可能会非常方便,例如,检查函数参数:
fun foo(node: Node): String? {
val parent = node.getParent() ?: return null
val name = node.getName() ?: throw IllegalArgumentException("name expected")
// ……
}
!! 操作符
!!操作符相当于一个非空检测屏蔽符,对于任何对象,使用!!后都会认为是非空的,如果是空的就出现NPE 异常
val l = b!!.length
类型安全转换
如果对象不是目标类型,那么常规类型转换可能会导致 ClassCastException。 另一个选择是使用安全的类型转换,如果尝试转换不成功则返回 null:
类型安全转换 as?
val aInt: Int? = a as? Int
可空类型的集合
如果你有一个可空类型元素的集合,并且想要过滤非空元素,你可以使用 filterNotNull 来实现:
val nullableList: List<Int?> = listOf(1, 2, null, 4)
val intList: List<Int> = nullableList.filterNotNull()
println(intList)//[1, 2, 4]
使用类型检测及自动类型转换
is 运算符检测一个表达式是否某类型的一个实例;后面不需要显示的转换就可以当成该类型使用
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// `obj` 在该条件分支内自动转换成 `String`
return obj.length
}
// 在离开类型检测分支后,`obj` 仍然是 `Any` 类型
return null
}
//甚至
fun getStringLength(obj: Any): Int? {
// `obj` 在 `&&` 右边自动转换成 `String` 类型
if (obj is String && obj.length > 0) {
return obj.length
}
return null
}
循环迭代
使用for
for 循环可以对任何提供迭代器(iterator)的对象进行遍历
获取值:
val items = listOf("apple", "banana", "kiwifruit")
for (item in items) {
println(item)
}
获取索引
val items = listOf("apple", "banana", "kiwifruit")
for (index in items.indices) {
println("item at $index is ${items[index]}")
}
索引和值一起
for ((index, value) in array.withIndex()) {
println("the element at $index is $value")
}
while
do while 和while和java一样;
break和continue
break 和continue使用也和java一样
条件语句
if表达式
与java 的if不一样的地方是kotlin的if可以是语句,也可以是表达式;因此kotlin不需要java中的三元运算符"条件 ? 然后 : 否则"
// 传统用法
var max = a
if (a < b) max = b
// With else
var max: Int
if (a > b) {
max = a
} else {
max = b
}
// 作为表达式
val max = if (a > b) a else b
if的分支可以是代码块,最后的表达式作为该块的值:
val max = if (a > b) {
print("Choose a")
a
} else {
print("Choose b")
b
}
when语句(相当于switch)
when语句相当于switch语句,简单用法
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // 注意这个块
print("x is neither 1 nor 2")
}
}
和if语句一样,可以是表达式,也可以是语句,但作为表达式时,符合条件的分支的值就是整个表达式的值,每个分支它的值是块中最后的表达式的值
如果其他分支都不满足条件将会求值 else 分支
注意: 如果 when 作为一个表达式使用,则必须有 else 分支, 除非编译器能够检测出所有的可能情况都已经覆盖了[例如,对于 枚举(enum)类条目与密封(sealed)类子类型]。
如果很多分支需要用相同的方式处理,则可以把多个分支条件放在一起,用逗号分隔
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
我们可以用任意表达式(而不只是常量)作为分支条件
when (x) {
parseInt(s) -> print("s encodes x")
else -> print("s does not encode x")
}
我们也可以检测一个值在(in)或者不在(!in)一个区间或者集合中:
when (x) {
in 1..10 -> {
println("x is in the range 1")
println("x is in the range 2")
}
in 200..300 -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
另一种可能性是检测一个值是(is)或者不是(!is)一个特定类型的值。注意: 由于智能转换,你可以访问该类型的方法与属性而无需任何额外的检测。
fun hasPrefix(x: Any) = when(x) {
is String -> x.startsWith("prefix")
else -> false
}
kotlin 1.3之后,还可以这样
fun Request.getBody() =
when (val response = executeRequest()) {
is Success -> response.body
is HttpError -> throw HttpException(response.status)
}