与Java不同的是,Kotlin只需要创建一个.kt的文件即可运行,无需创建类。

程序起点 main函数

简单版的main函数,.kt文件,写一个main()函数,即可运行

  1. fun main() {
  2. println("Hello world!")
  3. }

有入参的mian函数,负责接收环境变量等参数

  1. fun main(args: Array<String>) {
  2. println(args.contentToString())
  3. }

包定义和导入包

它不需要匹配目录和包:源文件可以任意放置在文件系统中。

  1. package my.demo
  2. import kotlin.text.*
  3. // ...

打印标准输出

  1. // 普通输出
  2. print("Hello ")
  3. print("world!")
  4. // 输出并换行
  5. println("Hello world!")

常量和变量

  1. //常量 val
  2. val a: Int = 1 // immediate assignment
  3. val b = 2 // `Int` type is inferred
  4. val c: Int // Type required when no initializer is provided
  5. c = 3 // deferred assignment
  6. //变量 var
  7. var x = 5 // `Int` type is inferred
  8. x += 1

函数

  1. //具有两个参数和返回类型的函数。
  2. //变量类型紧随其后用冒号隔开 符号人类习惯,先想变量名称在想类型
  3. fun sum(a: Int, b: Int): Int {
  4. return a + b
  5. }
  6. //函数主体可以是一种表达。推断其返回类型。可以省略花括号
  7. fun sum(a: Int, b: Int) = a + b
  8. //不返回任何有意义的值的函数。
  9. fun printSum(a: Int, b: Int): Unit {
  10. println("sum of $a and $b is ${a + b}")
  11. }
  12. //Unit可以省略返回类型。
  13. fun printSum(a: Int, b: Int) {
  14. println("sum of $a and $b is ${a + b}")
  15. }
  16. //默认参数
  17. fun read(
  18. b: ByteArray,
  19. off: Int = 0,
  20. len: Int = b.size,
  21. //如果默认参数后的最后一个参数是lambda,则可以将其作为指定参数或括号外传递:
  22. qux: () -> Unit,
  23. ) { /*...*/ }
  24. //泛型函数
  25. fun <T> singletonList(item: T): List<T> { /*...*/ }

无修复符号

使用无定形符号标记的功能也可以称为使用无缀符号(省略呼叫的点和括号)。修复功能必须满足以下要求:infix

  • 它们必须是成员功能或扩展功能
  • 它们必须具有单个参数。
  • 参数不得接受可变参数数,并且不得具有默认值
    1. infix fun Int.shl(x: Int): Int { ... }
    2. // calling the function using the infix notation
    3. 1 shl 2
    4. // is the same as
    5. 1.shl(2)

    与算术操作员、类型转换和操作员相比,Infix 函数呼叫的优先级较低。以下表示等效:rangeTo

    • 1 shl 2 + 3相当于1 shl (2 + 3)
    • 0 until n * 2相当于0 until (n * 2)
    • xs union ys as Set<*>相当于xs union (ys as Set<*>)

    另一方面,修复功能呼叫的优先级高于胸部操作员和 -和检查,以及其他一些操作员的优先级。这些表达式也等同于:&&``||``is``in

    • a && b xor c相当于a && (b xor c)
    • a xor b in c相当于(a xor b) in c

请注意,修复功能始终需要指定接收器和参数。当您使用无定形符号在当前接收器上调用方法时,请明确使用。这需要确保明确解析。this

  1. class MyStringCollection {
  2. infix fun add(s: String) { /*...*/ }
  3. fun build() {
  4. this add "abc" // Correct
  5. add("abc") // Correct
  6. //add "abc" // Incorrect: the receiver must be specified
  7. }
  8. }

尾部递归功能

科特林支持一种称为尾部递归的功能编程风格。对于通常使用循环的某些算法,您可以使用递归函数,而不会出现堆栈溢出的风险。当一个函数标记为修饰符并满足所需的正式条件时,编译器会优化递归,留下一个快速高效的基于循环的版本:tailrec

  1. val eps = 1E-10 // "good enough", could be 10^-15
  2. tailrec fun findFixPoint(x: Double = 1.0): Double =
  3. if (Math.abs(x - Math.cos(x)) < eps) x else findFixPoint(Math.cos(x))



此代码计算宇宙,这是一个数学常数。它只是反复调用,直到结果不再改变,产生指定精度的结果。生成的代码相当于这种更传统的样式:fixpoint``Math.cos``1.0``0.7390851332151611``eps

  1. val eps = 1E-10 // "good enough", could be 10^-15
  2. private fun findFixPoint(): Double {
  3. var x = 1.0
  4. while (true) {
  5. val y = Math.cos(x)
  6. if (Math.abs(x - y) < eps) return x
  7. x = Math.cos(x)
  8. }
  9. }



要符合修改器的资格,函数必须称为其执行的最后一个操作。当递归调用后有更多的代码时,您不能使用尾部递归,并且您不能在//块内使用它。目前,尾部递归由科特林为合资企业和科特林/本地支持。tailrec``try``catch``finally

类和对象

  1. //定义类
  2. class Shape
  3. //定义有属性的类
  4. class Rectangle(var height: Double, var length: Double) {
  5. var perimeter = (height + length) * 2
  6. }
  7. val rectangle = Rectangle(5.0, 2.0)
  8. println("The perimeter is ${rectangle.perimeter}")
  9. //允许类继承 添加关键字open
  10. open class Shape
  11. class Rectangle(var height: Double, var length: Double): Shape() {
  12. var perimeter = (height + length) * 2
  13. }

注释

  1. //单行注释
  2. /*
  3. 多行
  4. 注释
  5. */

字符串

  1. var a = 1
  2. //字符串模板 $可以直接取变量值
  3. val s1 = "a is $a"
  4. a = 2
  5. // ${}可以在字符串模板中进行计算和调用
  6. val s2 = "${s1.replace("is", "was")}, but now is $a"

条件表达式 if else

  1. fun maxOf(a: Int, b: Int): Int {
  2. if (a > b) {
  3. return a
  4. } else {
  5. return b
  6. }
  7. }
  8. 等同于
  9. fun maxOf(a: Int, b: Int) = if (a > b) a else b

循环 for

  1. val items = listOf("apple", "banana", "kiwifruit")
  2. for (item in items) {
  3. println(item)
  4. }
  5. 或者
  6. val items = listOf("apple", "banana", "kiwifruit")
  7. for (index in items.indices) {
  8. println("item at $index is ${items[index]}")
  9. }

循环 while

  1. val items = listOf("apple", "banana", "kiwifruit")
  2. var index = 0
  3. while (index < items.size) {
  4. println("item at $index is ${items[index]}")
  5. index++
  6. }

当 when

  1. //类似java的case语句,但更简单
  2. fun describe(obj: Any): String =
  3. when (obj) {
  4. 1 -> "One"
  5. "Hello" -> "Greeting"
  6. is Long -> "Long"
  7. !is String -> "Not a string"
  8. else -> "Unknown"
  9. }

范围 ..

  1. //输出从1到5
  2. for (x in 1..5) {
  3. print(x)
  4. }
  5. //x是否在1-y+1之间
  6. val x = 10
  7. val y = 9
  8. if (x in 1..y+1) {
  9. println("fits in range")
  10. }
  11. val list = listOf("a", "b", "c")
  12. if (-1 !in 0..list.lastIndex) {
  13. println("-1 is out of range")
  14. }
  15. if (list.size !in list.indices) {
  16. println("list size is out of valid list indices range, too")
  17. }
  18. //指定步长
  19. for (x in 1..10 step 2) {
  20. print(x)
  21. }
  22. println()
  23. for (x in 9 downTo 0 step 3) {
  24. print(x)
  25. }

存在 in

  1. for (item in items) {
  2. println(item)
  3. }
  4. when {
  5. "orange" in items -> println("juicy")
  6. "apple" in items -> println("apple is fine too")
  7. }
  8. val fruits = listOf("banana", "avocado", "apple", "kiwifruit")
  9. fruits
  10. .filter { it.startsWith("a") }
  11. .sortedBy { it }
  12. .map { it.uppercase() }
  13. .forEach { println(it) }

空指针问题解决 ?!

  1. //定义变量
  2. var helloB : String?
  3. //为空返回null ?
  4. helloB?.length
  5. //为空抛异常
  6. helloB!.length

参考资料