Kotlin Learning Notes

Just look through the basic grammers of Kotlin. To conclude, Kotlin seems so like Java, but has a lot of additional grammar sugar.

ep01

Why you should learn Kotlin?

  1. Complete null safety
  2. Use all Java libraries in Kotin, too
  3. Kotlin has coroutines

ep02 ep03

fun main() {
    println("Hello World")
}

ep04

fun main() {
    var myVariable: Int = 5
    println(myVariable)
}
fun main() {
    var myVariable: Int = 5
    println("The value of our variable is: $myVariable")
}
fun main() {
    var myVariable: Int = 5
    myVariable = 1
    println("The value of our variable is: $myVariable")
}
fun main() {
    var myVariable = 5
    println("The value of our variable is: $myVariable")
    myVariable = 1
    println("The value is now: $myVariable")
}

Because the tutorials are too basic, then I switch to official guideline.

Package definition and imports

package my.demo

import kotlin.text.*

// ...

Program entry point

fun main() {
    println("Hello world!")
}
fun main(args: Array<String>) {
    println(args.contentToString())
}

Print to the standard output

print("Hello ")
print("world!")
println("Hello world!")
println(42)

Functions

fun sum(a: Int, b: Int): Int {
    return a + b
}

fun main() {
    print("sum of 3 and 5 is ")
    println(sum(3, 5))
}
fun sum(a: Int, b: Int) = a + b

fun main() {
    println("sum of 19 and 23 is ${sum(19, 23)}")
}
fun printSum(a: Int, b: Int): Unit {
    println("sum of $a and $b is ${a + b}")
}

fun main() {
    printSum(-1, 8)
}

按:Unit 似乎和 Java 的 void 比较像。Unit 可以省略。

fun printSum(a: Int, b: Int) {
    println("sum of $a and $b is ${a + b}")
}

fun main() {
    printSum(-1, 8)
}

Variables

fun main() {
    val a: Int = 1  // immediate assignment
    val b = 2   // `Int` type is inferred
    val c: Int  // Type required when no initializer is provided
    c = 3       // deferred assignment
    println("a = $a, b = $b, c = $c")
}
fun main() {
    var x = 5 // `Int` type is inferred
    x += 1
    println("x = $x")
}
val PI = 3.14
var x = 0

fun incrementX() { 
    x += 1 
}

fun main() {
    println("x = $x; PI = $PI")
    incrementX()
    println("incrementX()")
    println("x = $x; PI = $PI")
}

Creating classes and instances

To define a class, use the class keyword.

class Shape

Properties of a class can be listed in its declaration or body.

class Rectangle(var height: Double, var length: Double) {
    var perimeter = (height + length) * 2
}

The default constructor with parameters listed in the class declaration is available automatically.

class Rectangle(var height: Double, var length: Double) {
    var perimeter = (height + length) * 2 
}
fun main() {
    val rectangle = Rectangle(5.0, 2.0)
    println("The perimeter is ${rectangle.perimeter}")
}

Inheritance between classes is declared by a colon (:). Classes are final by default; to make a class inheritable, mark it as open.

open class Shape

class Rectangle(var height: Double, var length: Double): Shape() {
    var perimeter = (height + length) * 2
}

Comments

Just like most modern languages, Kotlin supports single-line (or end-of-line) and multi-line (block) comments.

// This is an end-of-line comment

/* This is a block comment
   on multiple lines. */

Block comments in Kotlin can be nested.

/* The comment starts here
/* contains a nested comment *⁠/
and ends here. */

String templates

fun main() {
    var a = 1
    // simple name in template:
    val s1 = "a is $a" 

    a = 2
    // arbitrary expression in template:
    val s2 = "${s1.replace("is", "was")}, but now is $a"
    println(s2)
}

Conditional expressions

fun maxOf(a: Int, b: Int): Int {
    if (a > b) {
        return a
    } else {
        return b
    }
}

fun main() {
    println("max of 0 and 42 is ${maxOf(0, 42)}")
}
In Kotlin, if can also be used as an expression.

for loop

fun main() {
    val items = listOf("apple", "banana", "kiwifruit")
    for (item in items) {
        println(item)
    }
}
fun main() {
    val items = listOf("apple", "banana", "kiwifruit")
    for (index in items.indices) {
        println("item at $index is ${items[index]}")
    }
}

while loop

fun main() {
    val items = listOf("apple", "banana", "kiwifruit")
    var index = 0
    while (index < items.size) {
        println("item at $index is ${items[index]}")
        index++
    }
}

when expression

fun describe(obj: Any): String =
    when (obj) {
        1          -> "One"
        "Hello"    -> "Greeting"
        is Long    -> "Long"
        !is String -> "Not a string"
        else       -> "Unknown"
    }

fun main() {
    println(describe(1))
    println(describe("Hello"))
    println(describe(1000L))
    println(describe(2))
    println(describe("other"))
}

Ranges

Check if a number is within a range using in operator.

fun main() {
    val x = 10
    val y = 9
    if (x in 1..y+1) {
        println("fits in range")
    }
}

Check if a number is out of range.

fun main() {
    val list = listOf("a", "b", "c")

    if (-1 !in 0..list.lastIndex) {
        println("-1 is out of range")
    }
    if (list.size !in list.indices) {
        println("list size is out of valid list indices range, too")
    }
}

Iterate over a range.

fun main() {
    for (x in 1..5) {
        print(x)
    }
}

Or over a progression.

fun main() {
    for (x in 1..10 step 2) {
        print(x)
    }
    println()
    for (x in 9 downTo 0 step 3) {
        print(x)
    }
}

Collection

fun main() {
    val items = listOf("apple", "banana", "kiwifruit")
    for (item in items) {
        println(item)
    }
}

Check if a collection contains an object using in operator.

fun main() {
    val items = setOf("apple", "banana", "kiwifruit")
    when {
        "orange" in items -> println("juicy")
        "apple" in items -> println("apple is fine too")
    }
}

Using lambda expressions to filter and map collections:

fun main() {
    val fruits = listOf("banana", "avocado", "apple", "kiwifruit")
    fruits
        .filter { it.startsWith("a") }
        .sortedBy { it }
        .map { it.uppercase() }
        .forEach { println(it) }
}

Nullable values and null checks

A reference must be explicitly marked as nullable when null value is possible. Nullable type names have ? at the end.

Return null if str does not hold an integer:

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

Use a function returning nullable value:

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

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

    // Using `x * y` yields error because they may hold nulls.
    if (x != null && y != null) {
        // x and y are automatically cast to non-nullable after null check
        println(x * y)
    }
    else {
        println("'$arg1' or '$arg2' is not a number")
    }    
}

fun main() {
    printProduct("6", "7")
    printProduct("a", "7")
    printProduct("a", "b")
}
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
    }

    // x and y are automatically cast to non-nullable after null check
    println(x * y)
}

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

Type checks and automatic casts

fun getStringLength(obj: Any): Int? {
    if (obj is String) {
        // `obj` is automatically cast to `String` in this branch
        return obj.length
    }

    // `obj` is still of type `Any` outside of the type-checked branch
    return null
}

fun main() {
    fun printLength(obj: Any) {
        println("Getting the length of '$obj'. Result: ${getStringLength(obj) ?: "Error: The object is not a string"} ")
    }
    printLength("Incomprehensibilities")
    printLength(1000)
    printLength(listOf(Any()))
}
fun getStringLength(obj: Any): Int? {
    if (obj !is String) return null

    // `obj` is automatically cast to `String` in this branch
    return obj.length
}

fun main() {
    fun printLength(obj: Any) {
        println("Getting the length of '$obj'. Result: ${getStringLength(obj) ?: "Error: The object is not a string"} ")
    }
    printLength("Incomprehensibilities")
    printLength(1000)
    printLength(listOf(Any()))
}
fun getStringLength(obj: Any): Int? {
    // `obj` is automatically cast to `String` on the right-hand side of `&&`
    if (obj is String && obj.length > 0) {
        return obj.length
    }

    return null
}

fun main() {
    fun printLength(obj: Any) {
        println("Getting the length of '$obj'. Result: ${getStringLength(obj) ?: "Error: The object is not a string"} ")
    }
    printLength("Incomprehensibilities")
    printLength("")
    printLength(1000)
}

References:

  1. https://www.youtube.com/channel/UCKNTZMRHPLXfqlbdOI7mCkg
  2. https://kotlinlang.org/docs/basic-syntax.html

Kotlin Learning Notes
http://fanyfull.github.io/2021/12/13/Kotlin-Learning-Notes/
作者
Fany Full
发布于
2021年12月13日
许可协议