Kotlin for Java Developers 学习笔记
★Coursera 课程 Kotlin for Java Developers(由 JetBrains 提供)的学习笔记
”
From Java to Kotlin
Java 和 Kotlin 代码可以相互转化
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
class Person(val name: String, val age: Int)
Kotlin 被编译为 Java 字节码,所以从 Java 代码的层面看,这两者是一样的,都有一个 Constructor 和两个 Getter
也可以加上 data
修饰符,表示自动生成 equals
、hashCode
和 toString
这三个函数
data class Person(val name: String, val age: Int)
多个变量可以以 Pair 的形式赋值
val (description: String, color: Color) = Pair("hot", RED)
如果数据的类型在上下文中可以很明确地被推导出来,那么可以不用声明变量的类型
val (description: String, color: Color)
val (description, color)
多于 2 个 if … else … 时可以使用 when 关键字,类似于 switch,但又有细微区别
val (description, color) = when {
degrees < 10 -> Pair("cold", BLUE)
degrees < 25 -> Pair("mild", ORANGE)
else -> Pair("hot", RED)
}
基本语法
Kotlin 的代码也是从 main 函数开始
package intro
fun main() {
val name = "Kotlin"
println("Hello, $name!")
}
从 Kotlin 1.3 开始
fun main(args: Array<String>)
可以只写
fun main()
变量、常量与字符串模板
字符串模板 $variable
,${args.getOrNull(0)}
“变量”分为 val
和 var
,val
是只读的
Kotlin 是静态类型的语言,每一个变量都会有自己的类型,但是我们可以在代码中省略基本类型,编译器会自动推断
var s = "abc" // var s: String = "abc"
var v = 123 // var v: Int = 123
我们不能给一个类型的变量赋值另一个类型的数据,例如:字符串常量赋值给一个 Int 类型的变量 string
,这是一个编译时错误
var string = 1
string = "abc" // NOT ALLOWED是不允许的,我们不能把
val
不对数据做任何强加的限制,仍然可以改变其引用的数据,例如通过 list.add()
去修改一个被 val
修饰的列表,只要这个列表本身是允许被修改的
val list = mutableListOf("Java") // list.add() 可以往 List 中加东西
val list = listOf("Java") // list.add() 是不存在的
函数
fun max(a: Int, b: Int): Int {
return if (a > b) a else b
}
如果只有一句话(function wilth expression body),可以写成
fun max(a: Int, b: Int) = if (a > b) a else b
void
类型的函数在 Kotlin 中会以 Unit
的形式返回
Kotlin 的函数可以定义在任何地方:顶层、类的成员、函数中定义另一个函数
调用顶层函数相当于 Java 中的 static 函数
// MyFile.kt
package intro
fun foo() = 0
//UsingFoo.java
package other;
import intro.MyFileKt;
public class UsingFoo {
public static void main(String[] args) {
MyFileKt.foo();
}
}
为变量提供默认值,不再需要重载各种函数
fun displaySeparatpr(character: Char = '*', size: Int = 10) {
repeat(size) {
print(character)
}
}
displaySeparator() // **********
displaySeparator(size = 5) // *****
displaySeparator(3, '5') // WON'T COMPILE
displaySeparator(size = 3, character = '5') // 555
分支
在 Kotlin 中,if
是表达式
val max = if (a > b) a else b
没有三元表达式
(a > b) ? a : b
注意与 Python 的区别
max = a if a > b else b
在 Kotlin 中,when
可以当作 switch
使用,不需要 break
switch (color) {
case BLUE:
System.out.println("cold")
break;
case ORANGE:
System.out.println("mild")
break;
default:
System.out.println("hot")
}
when (color) {
BLUE -> println("cold")
ORANGE -> println("mild")
else -> println("hot")
}
可以使用任何类型,可以用来判断多个条件
fun response(input: String) = when (input) {
"y", "yes" -> "Agree"
"n", "no" -> "Sorry"
else -> "Not Understand"
}
可以做类型检查
if (pet instanceof Cat) {
((Cat) pet).meow();
} else if (pet instanceof Dog) {
Dog dog = (Dog) pet;
dog.woof();
}
when (pet) {
is Cat -> pet.meow()
is Dog -> pet.woof()
}
可以不需要参数
fun updateWeather(degrees: Int) {
val (desc, color) = when {
degrees < 5 -> "cold" to BLUE
degrees < 23 -> "mild" to ORANGE
else -> "hot" to RED
}
}
循环
val map = mapOf(1 to "one", 2 to "two", 3 to "three")
for ((key, value) in map) {
println("$key = $value")
}
val list = listOf("a", "b", "c")
for ((index, element) in list.withIndex()) {
println("$index: $element")
}
for (i in 1..9) // 1 2 3 4 5 6 7 8 9
for (i in 1 until 9) // 1 2 3 4 5 6 7 8
for (ch in "abc")
for (i in 9 downTo 1 step 2) // 9 7 5 3 1
拓展函数
fun String.lastChar() = get(length - 1)
val c: Char = "abc".lastChar()
也可以直接在 Java 中使用 Kotlin 中定义的拓展函数
import lastChar from ExtensionFunctions.kt;
char c = lastChar("abc");
常用的有 withIndex
、getOrNull
、joinToString
、until
、to
、eq
、toInt
等等
val set = hashSetOf(1, 7, 53)
println(set.javaClass) // class java.util.HashSet
fun main(args: Array<String>) {
println("Hello, ${args.getOrNull(0)}!")
}
val regex = """\d{2}\.\d{2}\.\d{4}""".toRegex()
regex.matches("15.02.2016") // true
regex.matches("15.02.16") // false
特别的,until
和 to
这种,本身是需要通过 .
和 ()
调用的
1.until(10)
"Answer".to(42)
但是因为原型声明的时候允许 infix
infix fun Int.until(to: Int) = IntRange
infix fun <A, B> A.to(that: B) = pair(this, that)
所以可以省略 .
和 ()
1 until 10
"Answer" to 42
成员函数比拓展函数的优先级高,例如下例会输出 1
,并得到一个警告,说 entension is shadowed by a member
class A {
fun foo() = 1
}
fun A.foo() = 2 // Warning: Extension is shadowed by a member
A().foo() // 1
但是我们可以重载一个拓展函数
class A {
fun foo() = "member"
}
fun A.foo(i: Int) = "extension($i)"
A().foo(2) // extension(2)
标准库
Kotlin 的标准库包括 Java 标准库和一些常用的拓展函数
没有所谓的 Kotlin SDK,只有 Java 的 JDK 和一些 extensions
Nullability
现代的编程语言应该把 Null Pointer Exception 变成编译时错误,而不是运行时错误
val s1: String = "always not null" // 不可以 = null
val s2: String? = null // 或者 = "a string"
对于一个可能为 null 的变量,我们应该始终用 if 语句检查
if (s != null) {
s.length
}
在 Kotlin 中。可以使用 ?
来简化访问,如果对象为 null,则运行结果为 null,返回类型是 nullable 的基本类型
val length: Int? = s?.length
如果只想要基本类型,可以使用 elvis 运算符( elvis 来自 Groove)
val length: Int = s?.length ?: 0
可以使用 !!
强制抛出 NPE
elvis 的优先级比加减法低
val x: Int? = 1
val y: Int = 2
val z1 = x ?: 0 + y // 1
val z2 = x ?: (0 + y) // 1
val z3 = (x ?: