Kotlin
是一种现代但已经成熟的编程语言,可以在 JVM(Java 虚拟机) 上运行的静态类型编程语言。它简洁、安全、可与 Java 和其他语言互操作,并提供多种方法来在多个平台之间重用代码以进行高效编程。它的一些基本特性,包括类、继承、条件语句和循环结构。
我们先来看看使 Kotlin
语言的一些主要特性:空安全、数据类、扩展函数和字符串模板。
1. 基本语法
Kotlin
的基本语法与 Java
有一些相似之处(如,定义包的方式相同)。
主要来看看它们的差异:
- 定义函数
fun sum(a: Int, b: Int): Int {
return a + b
}
- 定义变量
// 只读变量是使用关键字 val 定义的。它们只能被赋值一次。
val a: Int = 1
val b = 2
val c: Int
c = 3
// 可以重新分配的变量使用 var 关键字
var x = 5
x += 1
2. 可空值和空检查
在 Kotlin 中,类型系统区分可以为空的引用(nullable references)和不能为空的引用(non-null references)。
例如,String 类型的常规变量不能为 null:
var a: String = "abc" // 默认是非空引用
a = null // Error 编译失败
要允许空值,通过 String?
将变量声明为可空字符串:
var b: String? = "abc" // 声明为可空引用
b = null // ok 正常编译
3. 字符串模板
Kotlin 语言的一个非常好的特性是可以使用字符串模板。它非常有用,因为我们不需要手动连接字符串:
var a = 1
// 在模板中使用变量的值
val s1 = "a is $a"
a = 2
// 模板中也可以使用表达式:
val s2 = "${s1.replace("is", "was")}, but now is $a"
4. 条件语句
在 Kotlin 中,if
是一个表达式:它返回一个值。
var max = a
if (a < b) max = b
// With else
var max: Int
if (a > b) {
max = a
} else {
max = b
}
// As expression
val max = if (a > b) a else b
Kotlin 还有一个非常有用的 when
表达式作为高级 switch
语句
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> {
print("x is neither 1 nor 2")
}
}
5. 循环结构
在 Kotlin 中,可以使用标准的 for..in 结构来循环遍历集合:
for (item: Int in ints) {
// ...
}
如果我们想迭代一个整数范围,我们可以使用范围结构:
请注意,此示例中在两侧的范围都包含在内。 step 参数是可选的
for (i in 1..3) {
println(i)
} // 输出 1 2 3
for (i in 6 downTo 0 step 2) {
println(i)
} // 输出 6 4 2 0
6. 类
Kotlin 中的类使用关键字 class
声明:
class Person { /*...*/ }
// header 和 body 都是可选的;如果类没有主体,则可以省略大括号。
class EmptyClz
Kotlin 中的类可以有一个主构造函数和一个或多个辅助构造函数。
// 主构造函数是类头的一部分,它位于类名和可选类型参数之后。
class Person constructor(firstName: String) { /*...*/ }
// 如果主构造函数没有任何注释或可见性修饰符,则可以省略`constructor`关键字:
class Person(name: String) {
}
// Kotlin 有一个简洁的语法来声明属性并从主构造函数初始化它们:
class InitOrderDemo(val name: String, var age: Int) {
// 主构造函数不能包含任何代码。初始化代码可以放在以 init 关键字为前缀的初始化程序块中。
init {
println("First initializer block that prints $name")
}
}
// 如果构造函数有注解或可见性修饰符,则构造函数关键字是必需的
class Customer public @Inject constructor(name: String) { /*...*/ }
// 如果您不希望类具有公共构造函数,声明一个具有非默认可见性的空主构造函数:
class DontCreateMe private constructor () { /*...*/ }
7. 继承
默认情况下,Kotlin 的类是不允许扩展的,相当于 Java 中标记为
final
的类。
为了指定一个类对扩展是开放的,您将在定义类时使用 open
关键字。
open class Base(p: Int)
class Derived(p: Int) : Base(p)
我们还需将父类方法表示为 open
。这样它才允许被覆盖。
open class Shape {
open fun draw() { /*...*/ }
fun fill() { /*...*/ }
}
class Circle() : Shape() {
override fun draw() { /*...*/ }
}
8. 数据类/Data classes
在 Kotlin 中一个非常好的语言结构是数据类。这些类的目的是只保存数据。
data class User(val name: String, val age: Int)
// 编译器将根据声明的属性为我们创建方法 hashCode()、equals()、toString()、componentN()、copy()。
// 为数据类生成的 Component 函数可以在解构声明中使用它们:
val jane = User("Jane", 35)
val (name, age) = jane
println("$name, $age years of age")
// 使用 copy 函数复制对象,允许更改其某些属性,同时保持其余属性不变:
val jack = User(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)
9. 集合/Collections
Kotlin 中有两种类型的集合:可变的和不可变的。
// 当我们创建不可变集合时,意味着它是只读的:
val numbers = listOf(1, 2, 3, 4)
// 当我们想要创建一个可变集合时,需要使用 mutableListOf() 方法:
val mNumbers = mutableListOf(1, 2, 3)
mNumbers.add(4)
// 可变列表具有 add() 方法,因此我们可以向其附加一个元素。
还有其他类型集合的等效方法:mutableMapOf()
、mapOf()
、setOf()
、mutableSetOf()
10. 异常/Exceptions
Kotlin 的异常处理机制与 Java 中的机制非常相似。所有异常类都扩展了 Throwable。异常必须有一个消息、堆栈跟踪和一个可选的原因。
// 使用 throw 表达式抛出异常对象
throw Exception("exception message")
// 使用 try...catch 完成的异常的处理
try {
// ...
}
catch (e: SomeException) {
// ...
}
finally {
// ...
}
Kotlin 中的每个异常都是未经检查的,这意味着编译器不会强迫我们捕获它们。
11. Lambda 表达式
在 Kotlin 中,我们可以定义 lambda
函数并将它们作为参数传递给其他函数。
让我们看看如何定义一个简单的 lambda:
val sum = { x: Int, y: Int -> x + y }
ints.filter { it > 0 }
12. 扩展函数
Kotlin 提供了使用新功能扩展类的能力,而无需从类继承或使用装饰器等设计模式。
要声明扩展函数,在函数名称前面加上被扩展的类型。下面为 MutableList
fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // 'this' corresponds to the list
this[index1] = this[index2]
this[index2] = tmp
}
// 现在,您可以在任何 MutableList<Int> 上调用该函数:
val list = mutableListOf(1, 2, 3)
list.swap(0, 2)
13. Kotlin/Java 互相调用
Kotlin 的设计考虑到了与 Java 互相调用。现有的 Java 代码可以很自然地从 Kotlin 中调用,而 Kotlin 代码在 Java 中也可以很顺利地使用。
// Sample.kt 中定义定义顶层函数
package com.sample.app
fun demo(){ println("demo") }
// java 调用
public class TestJava {
public static void main(String[] args) {
SampleKt.demo();
}
}
通过 @file:JvmName("类名")
告诉编译器生成的类名,Java 代码就可以直接使用指定的类名调用了。
@file:JvmName("Sample")
package com.sample.app
fun demo(){ println("demo") }
// java 调用
public class TestJava {
public static void main(String[] args) {
Sample.demo();
}
}