Kotlin Basic Syntax

Kotlin files end with.ktas the suffix.

Package declaration

The beginning of a code file is generally a package declaration:

package com.example.main

import java.util.*

fun test() {}
class Example {}

Kotlin source files do not require a matching directory and package; source files can be placed in any file directory.

In the above example, the full name of test() is com.example.main.test, and the full name of Example is com.example.main.Example.

If no package is specified, it defaults to thedefaultpackage.

Default imports

Several packages are imported by default into every Kotlin file:

  • kotlin.*
  • kotlin.annotation.*
  • kotlin.collections.*
  • kotlin.comparisons.*
  • kotlin.io.*
  • kotlin.ranges.*
  • kotlin.sequences.*
  • kotlin.text.*

Function definition

Function definitions use the keyword fun, and the parameter format is: parameter : type

fun sum(a: Int, b: Int): Int {   // Int 参数,返回值 Int
    return a + b
}

An expression as a function body, with the return type automatically inferred:

fun sum(a: Int, b: Int) = a + b

public fun sum(a: Int, b: Int): Int = a + b   // public 方法则必须明确写出返回类型

A function with no return value (similar to void in Java):

fun printSum(a: Int, b: Int): Unit { 
    print(a + b)
}


// 如果是返回 Unit类型,则可以省略(对于public方法也是这样):
public fun printSum(a: Int, b: Int) { 
    print(a + b)
}

Variable-length parameter function

A function's variable-length parameters can be marked with thevarargkeyword:

fun vars(vararg v:Int){
    for(vt in v){
        print(vt)
    }
}

// 测试
fun main(args: Array<String>) {
    vars(1,2,3,4,5)  // 输出12345
}

lambda (anonymous function)

lambda expression usage example:

// 测试
fun main(args: Array<String>) {
    val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
    println(sumLambda(1,2))  // 输出 3
}

Defining constants and variables

Mutable variable definition: var keyword

var <标识符> : <类型> = <初始化值>

Immutable variable definition: val keyword, a variable that can only be assigned once (similar to a variable modified by final in Java)

val <标识符> : <类型> = <初始化值>

Both constants and variables can be without initial values, but they must be initialized before being referenced.

The compiler supports automatic type inference, that is, when declaring, you can omit the type and let the compiler infer it.

val a: Int = 1
val b = 1       // 系统自动推断变量类型为Int
val c: Int      // 如果不在声明时初始化则必须提供变量类型
c = 1           // 明确赋值


var x = 5        // 系统自动推断变量类型为Int
x += 1           // 变量可修改

Comments

Kotlin supports single-line and multi-line comments, as shown in the following example:

// This is a single-line comment

/* This is a multi-line
   block comment. */

Unlike Java, block comments in Kotlin allow nesting.


String templates

$ represents a variable name or variable value

$varName represents the variable value

${varName.fun()} represents the return value of the variable's method:

var a = 1
// 模板中的简单名称:
val s1 = "a is $a" 

a = 2
// 模板中的任意表达式:
val s2 = "${s1.replace("is", "was")}, but now is $a"

NULL checking mechanism

Kotlin's null-safe design requires null-check handling when using parameters declared as nullable. There are two handling methods: adding !! after the field throws a null exception like Java; the other way is adding ? after the field, which can be left unhandled and the return value isnullor with?:for null-check handling.

//类型后面加?表示可为空
var age: String? = "23" 
//抛出空指针异常
val ages = age!!.toInt()
//不做处理返回 null
val ages1 = age?.toInt()
//age为空返回-1
val ages2 = age?.toInt() ?: -1

When a reference may be null, the corresponding type declaration must be explicitly marked as nullable.

When the string in str is not an integer, it returns null:

fun parseInt(str: String): Int? {
  // ...
}

The following example demonstrates how to use a function whose return value can be null:

fun parseInt(str: String): Int? {
    return str.toIntOrNull()
}

fun printProduct(arg1: String, arg2: String) {
    val x = parseInt(arg1)
    val y = parseInt(arg2)

    // 直接使用 `x * y` 会导致错误, 因为它们可能为 null
    if (x != null && y != null) {
        // 在进行过 null 值检查之后, x 和 y 的类型会被自动转换为非 null 变量
        println(x * y)
    }
    else {
        println("'$arg1' or '$arg2' is not a number")
    }    
}

fun main() {
    printProduct("6", "7")
    printProduct("a", "7")
    printProduct("a", "b")
}

Or:

fun parseInt(str: String): Int? {
    return str.toIntOrNull()
}

fun printProduct(arg1: String, arg2: String) {
    val x = parseInt(arg1)
    val y = parseInt(arg2)
    
    // ...
    if (x == null) {
        println("Wrong number format in arg1: '$arg1'")
        return
    }
    if (y == null) {
        println("Wrong number format in arg2: '$arg2'")
        return
    }

    // 在进行过 null 值检查之后, x 和 y 的类型会被自动转换为非 null 变量
    println(x * y)
}

fun main() {
    printProduct("6", "7")
    printProduct("a", "7")
    printProduct("99", "b")
}

Type checking and automatic type conversion

We can use theisoperator to check whether an object is an instance of a specified type (similar to the instanceof keyword in Java).

if (obj is Type) {
    // 如果 obj 是 Type 类型,则可以直接使用 Type 类型的属性和方法
} else {
    // 处理其他类型情况
}

WhenisWhen the check passes, Kotlin automaticallyobjtreats it as the specified type, so inifthe branch of the statement, there is no need to explicitly perform type conversion. This is calledsmart type conversion.。

Example

fun main() {
    val obj: Any = "Hello, Kotlin"

    if (obj is String) {
println("string length: ${obj.length}") // Here `obj` has been smart-cast to `String`
    } else {
println("Not a string type")
    }
}

In this example, ifobjYesStringtype,isoperator returnstrue, Kotlin willobjrecognize it asString, so it can directly accessStringthe properties and methods of the type.

More applications:

fun getStringLength(obj: Any): Int? {
  if (obj is String) {
    // 做过类型判断以后,obj会被系统自动转换为String类型
    return obj.length 
  }

  //在这里还有一种方法,与Java中instanceof不同,使用!is
  // if (obj !is String){
  //   // XXX
  // }

  // 这里的obj仍然是Any类型的引用
  return null
}

Or

fun getStringLength(obj: Any): Int? {
  if (obj !is String)
    return null
  // 在这个分支中, `obj` 的类型会被自动转换为 `String`
  return obj.length
}

You can even

fun getStringLength(obj: Any): Int? {
  // 在 `&&` 运算符的右侧, `obj` 的类型会被自动转换为 `String`
  if (obj is String && obj.length > 0)
    return obj.length
  return null
}

Ranges

Range expressions are formed by the operator form..of the rangeTo function, supplemented by in and !in.

Ranges are defined for any comparable type, but for integral primitive types, they have an optimized implementation. The following are some examples of using ranges:

for (i in 1..4) print(i) // 输出“1234”

for (i in 4..1) print(i) // 什么都不输出

if (i in 1..10) { // 等同于 1 <= i && i <= 10
    println(i)
}

// 使用 step 指定步长
for (i in 1..4 step 2) print(i) // 输出“13”

for (i in 4 downTo 1 step 2) print(i) // 输出“42”


// 使用 until 函数排除结束元素
for (i in 1 until 10) {   // i in [1, 10) 排除了 10
     println(i)
}

Example test

fun main(args: Array<String>) {
    print("循环输出:")
    for (i in 1..4) print(i) // 输出“1234”
    println("\n----------------")
    print("设置步长:")
    for (i in 1..4 step 2) print(i) // 输出“13”
    println("\n----------------")
    print("使用 downTo:")
    for (i in 4 downTo 1 step 2) print(i) // 输出“42”
    println("\n----------------")
    print("使用 until:")
    // 使用 until 函数排除结束元素
    for (i in 1 until 4) {   // i in [1, 4) 排除了 4
        print(i)
    }
    println("\n----------------")
}

Output result:

循环输出:1234
----------------
设置步长:13
----------------
使用 downTo:42
----------------
使用 until:123
----------------
Other extensions