Kotlin Là Gì?
Kotlin Là Gì?

Android Kotlin 101: Viết chương trình đầu tiên của bạn

Hành trình vạn dặm từ bước chân đầu tiên. Hãy bắt đầu chương trình Kotlin đầu tiên của bạn từ Blog Post này nhé. Chúc bạn thành công và trở thành một Software Engineer tốt!

Cài đặt IDE

Truy cập đường link: Tải IDE bản Community

Hàm Main – Entry Point

Tạo New Project Kotlin với IntelliJ IDE
Tạo New Project Kotlin với IntelliJ IDE
Hàm main trong chương trình Kotlin
Hàm main trong chương trình Kotlin

Hãy bắt đầu bằng dòng lệnh và nhấn nút Run ở bên trái hàm main

fun main() {
    println("Hello Kotlin!")
}

Kiểu dữ liệu Primary

fun main() {
    val integerVariable: Int = 0
    println("Integer Variable: $integerVariable")
    val floatVariable: Float = 1.111f
    println("Float Variable: $floatVariable")
    val doubleVariable: Double = 3.14159888
    println("Double Variable: $doubleVariable")
    val longVariable: Long = 9191488142L
    println("Long Variable: $longVariable")
    val shortVariable: Short = 32767
    println("Short Variable: $shortVariable")
    val booleanVariable: Boolean = true
    println("Boolean Variable: $booleanVariable")
    val stringVariable: String = "Hello, Kotlin!"
    println("String Variable: $stringVariable")
    val charVariable: Char = 'A'
    println("Char Variable: $charVariable")
    val byteVariable: Byte = 127
    println("Byte Variable: $byteVariable")
}

Kotlin cung cấp đầy đủ các kiểu dữ liệu Primary cần thiết để Lập trình viên có thể viết nên chương trình của họ. Bạn hãy yên tâm về điều này.

Toán tử trên các kiểu dữ liệu cơ sở

fun main() {
    val integerVariable: Int = 28283
    val integerVariable2: Int = 168
    println("Integer Variable: $integerVariable")
    println("Integer Variable 2: $integerVariable2")
    val addedIntegerVariable: Int = integerVariable + integerVariable2
    val subtractedIntegerVariable: Int = integerVariable - integerVariable2
    val multipliedIntegerVariable: Int = integerVariable * integerVariable2
    val dividedIntegerVariable: Int = integerVariable / integerVariable2
    val remainderIntegerVariable: Int = integerVariable % integerVariable2
    println("Added: $addedIntegerVariable")
    println("Subtracted: $subtractedIntegerVariable")
    println("Multiplied: $multipliedIntegerVariable")
    println("Divided: $dividedIntegerVariable")
    println("Remainder: $remainderIntegerVariable")
} // Similar for other data types

Kotlin cung cấp đầy đủ các toán tử tính toán cho các kiểu dữ liệu cơ sở. Bạn hãy thử với các kiểu dữ liệu khác như Float, Double, String, Byte, Short … để kiểm chứng nhé.

Toán tử trên Bit

Trong thực tế phát triển dự án cả Backend lẫn Desktop, Mobile app bằng ngôn ngữ Kotlin chúng ta rất hiếm khi sử dụng đến công cụ Bitwise (Toán tử trên Bit). Tuy nhiên mình vẫn sẽ cung cấp thông tin để các bạn được nắm và tập luyện khi cần.

fun main() {
    val number1 = 12
    val number2 = 25

    // Bitwise AND
    val andResult = number1 and number2
    println("Result of Bitwise AND is $andResult")

    // Bitwise OR
    val orResult = number1 or number2
    println("Result of Bitwise OR is $orResult")

    // Bitwise XOR
    val xorResult = number1 xor number2
    println("Result of Bitwise XOR is $xorResult")

    // Bitwise Inversion (NOT)
    val invResult = number1.inv()
    println("Result of Bitwise Inversion (NOT) is $invResult")

    // Bitwise Left Shift
    val leftShiftResult = number1 shl 2
    println("Result of Bitwise Left Shift is $leftShiftResult")

    // Bitwise Right Shift
    val rightShiftResult = number1 shr 2
    println("Result of Bitwise Right Shift is $rightShiftResult")
}

Các toán tử được Kotlin cung cấp và sử dụng một cách dễ dàng.

Khai báo Nullable, NonNullable

NULL là 1 khái niệm xuất hiện trong hầu hết tất cả các ngôn ngữ lập trình ngày nay. Việc xử lý Null check là cần thiết và nhất thiết phải có cho tất cả mọi Logic trong dự án.

Kotlin xử lý vấn đề này bằng cách định nghĩa mỗi biến khi khai báo đều được phải được xác định là 1 Nullable hoặc NonNullable. Điều này giúp cho quá trình code trở nên thuận tiện và dễ dàng hơn. Các xử lý Null Check có thể được lược bỏ nếu ta đảm bảo rằng biến đã khai báo là một NonNullable.

Một biến Nullable khi truy cập sẽ phải sử dụng toán tử ?. để gọi các properties bên trong chúng. Toán tử này sẽ trả về NULL nếu biến được gọi là NULL hoặc property được gọi ra mang giá trị NULL

class MyKotlinObject {
    val myKotlinProperty: String = "Hello, Kotlin!"
    val myNullKotlinProperty: String? = null
}

fun main() {
    val myNonNullKotlinObject = MyKotlinObject()
    println("myNonNullKotlinObject.myKotlinProperty: ${myNonNullKotlinObject.myKotlinProperty}")
    println("myNonNullKotlinObject.myNullKotlinProperty: ${myNonNullKotlinObject.myNullKotlinProperty}")
    val myNullKotlinObject: MyKotlinObject? = null
    println("myNullKotlinObject?.myKotlinProperty: ${myNullKotlinObject?.myKotlinProperty}")
    println("myNullKotlinObject?.myNullKotlinProperty: ${myNullKotlinObject?.myNullKotlinProperty}")
}

Ví dụ cách sử dụng Null và NonNullable trong Kotlin – Android Mastery by Danh Trần

Khai báo Mutable, Immutable

Kotlin là một ngôn ngữ rất chặt chẽ. Và sự chặt chẽ đó thể hiện ở cách Kotlin quản lý các biến MutableImmutable trong chương trình của Lập trình viên.

Immutable dịch ra tiếng Việt có nghĩa là Bất biến. Có nghĩa là bất kỳ một biến nào trong chương trình được khai báo với kiểu Immutable đều sẽ không thay đổi giá trị trong suốt vòng đời của chúng.

Để khai báo một biến Immutable trong Kotlin ta dùng từ khóa val đứng trước tên biến.

class MyKotlinObject {
    val myKotlinProperty: String = "Hello, Kotlin!"
    val myNullKotlinProperty: String? = null
}

fun main() {
    val myNonNullKotlinObject = MyKotlinObject()
    val myNullKotlinObject: MyKotlinObject? = null
    myNullKotlinObject = myNonNullKotlinObject // Compilation error
}

Một biến Immutable sẽ chỉ được khai báo giá trị 1 lần duy nhất và không bao giờ được gán lại trong suốt vòng đời của nó.

Ngược lại với Immutable , Kotlin cung cấp cách khai báo biến Mutable để biểu thị các biến có thể được gán lại giá trị nhiều lần, trên nhiều Thread, Coroutines khác nhau trong suốt vòng đời của chúng trong chương trình.

Để khai báo một biến Mutable , ta dùng từ khóa var đứng trước tên biến.

class MyKotlinObject {
    val myKotlinProperty: String = "Hello, Kotlin!"
    val myNullKotlinProperty: String? = null
}

fun main() {
    var myNonNullKotlinObject: MyKotlinObject = MyKotlinObject()
    var myNullKotlinObject: MyKotlinObject? = null
    myNullKotlinObject = myNonNullKotlinObject
    myNonNullKotlinObject = MyKotlinObject()
}

Khi một biến Mutable được khai báo, chúng sẽ tự do được gán các giá trị mới phù hợp với kiểu dữ liệu đã khai báo trong suốt vòng đời trên chương trình.

class MyKotlinObject {
    val myKotlinProperty: String = "Hello, Kotlin!"
    val myNullKotlinProperty: String? = null
}

fun main() {
    var myNonNullKotlinObject: MyKotlinObject = MyKotlinObject()
    var myNullKotlinObject: MyKotlinObject? = null
    myNonNullKotlinObject = myNullKotlinObject // Compile Error
}

Chương trình sẽ không thể biên dịch được nếu bạn cố gán một biến Mutable kiểu NonNullable cho một biến Nullable

Câu lệnh điều kiện, vòng lặp trong Kotlin

Tương tự với các ngôn ngữ lập trình khác. Kotlin cung cấp các công cụ cho lập trình viên dễ dàng xây dựng Logic cho chương trình của họ. Hơn thế nữa trong Kotlin ta có những cú pháp rút gọn tiện dụng hơn rất nhiều.

fun main() {
    // readLine() is used to read input from the user
    val number: Int = readlnOrNull()?.toIntOrNull() ?: 0
    
    println("Simple if statement")
    if (number > 5) {
        println("$number is greater than 5")
    } else {
        println("$number is not greater than 5")
    }

    println("Advanced if statement")
    val checkNumberString = if (number > 5) {
        "$number is greater than 5"
    } else {
        "$number is not greater than 5"
    }

    // out standing if
    println(
        if (number > 5) {
            "$number is greater than 5"
        } else {
            "$number is not greater than 5"
        }
    )
}

Ví dụ cách sử dụng if else trong Kotlin – Android Mastery

fun main() {
    println("Enter the start value:")
    val start = readLine()?.toIntOrNull()
    println("Enter the end value:")
    val end = readLine()?.toIntOrNull()

    if (start != null && end != null && start <= end) {
        for (i in start..end) {
            println("Current number is: $i")
        }
    } else {
        println("Invalid input. Please enter valid start and end values where start is less than or equal to end.")
    }
}

Ví dụ cách sử dụng for loop trong Kotlin – Android Mastery

fun main() {
    println("Enter the start value:")
    val start = readLine()?.toIntOrNull()
    println("Enter the end value:")
    val end = readLine()?.toIntOrNull()

    if (start != null && end != null && start <= end) {
        var i = start
        while (i <= end) {
            println("Current number is: $i")
            i++
        }
    } else {
        println("Invalid input. Please enter valid start and end values where start is less than or equal to end.")
    }
}

Ví dụ cách sử dụng while loop trong ngôn ngữ Kotlin – Android Mastery

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

		// Simple when
    when (obj) {
        is String -> println("The object is a String. Value: $obj")
        is Int -> println("The object is an Integer. Value: $obj")
        else -> println("The object is of an unknown type.")
    }
    
    // Advanced when
    val ret = when (obj) {
        is String -> "The object is a String. Value: $obj"
        is Int -> "The object is an Integer. Value: $obj"
        else -> "The object is of an unknown type."
    }
}

Ví dụ cách sử dụng when condition trong ngôn ngữ Kotlin – Android Mastery

Khai báo hàm trong Kotlin

Hàm (function) là một yếu tố không thể thiếu trong Kotlin. Ngôn ngữ lập trình Kotlin cung cấp cho ta rất nhiều cách khai báo và sử dụng hàm (function) một cách linh hoạt.

fun addNumbers(num1: Int, num2: Int): Int {
    return num1 + num2
}

fun main() {
    val sum = addNumbers(5, 3)
    println("The sum is: $sum")
}

Cách khai báo hàm đơn giản nhất trong Kotlin – Android Mastery

fun outerFunction() {
    fun innerFunction() {
        println("This is the inner function.")
    }

    println("This is the outer function.")
    innerFunction()
}

fun main() {
    outerFunction()
}

Cách khai báo inner function trong Kotlin – Android Mastery

val multiply = { num1: Int, num2: Int -> num1 * num2 }

fun main() {
    val result = multiply(5, 3)
    println("The result is: $result")
}

Cách khai báo hàm là 1 Lambda Expression trong Kotlin (Cách viết ngắn gọn, được nhiều lập trình viên sử dụng) – Android Mastery

Hướng đối tượng trong ngôn ngữ Kotlin

Hướng đối tượng là 1 chủ đề cơ bản trong lập trình. Ở đây ý mình muốn nói Hướng đối tượng là 1 phương pháp lập trình, chúng ta có thể lập trình hướng tối tượng với mọi ngôn ngữ. Tuy nhiên 1 số ngôn ngữ sẽ hỗ trợ việc lập trình hướng đối tượng mạnh hơn 1 số ngôn ngữ khác. Ví dụ ở đây là Kotlin, C++, C#

Kotlin hỗ trợ lập trình Hướng đối tượng với đầy đủ các tính năng: Khai báo Class, Interface, Kế thừa, Đa hình. Ngoài ra Kotlin còn hỗ trợ các tính năng riêng độc đáo của mình như data class , sealed class , Object , Enum class

Hãy tham khảo các đoạn code bên dưới đây

enum class Direction(val direction: String) {
    LEFT("LEFT"),
    RIGHT("RIGHT"),
    FORWARD("FORWARD"),
    BACKWARD("BACKWARD"),
    STOP("STOP")
}
interface Drivable {
    fun drive(direction: Direction)
}
interface Movable {
    fun speedUp()
    fun speedDown()
}
class Car : Drivable, Movable {

    private var speed: Int = 0

    companion object {
        const val MAX_SPEED = 60
        const val MIN_SPEED = 0
    }

    override fun drive(direction: Direction) {
        println("Driving the car turn $direction")
    }

    override fun speedUp() {
        speed++
        if (speed > MAX_SPEED) {
            speed = MAX_SPEED
        }
        println("Speeding up the car $speed")
    }

    override fun speedDown() {
        speed--
        if (speed < MIN_SPEED) {
            speed = MIN_SPEED
        }
        println("Speeding down the car $speed")
    }
}

Ví dụ của OOP trong Kotlin – Android Mastery

data class User(val name: String, val age: Int)
sealed class Expr {
    data class Const(val number: Double) : Expr()
    data class Sum(val e1: Expr, val e2: Expr) : Expr()
    object NotANumber : Expr()
}

fun main() {
    // Using data class
    val user = User("Dan Tech 0xFF", 30)
    println(user)

    // Using sealed class
    val expr1: Expr = Expr.Const(10.0)
    val expr2: Expr = Expr.Sum(expr1, Expr.Const(20.0))
    val expr3: Expr = Expr.NotANumber

    val result = when (expr2) {
        is Expr.Const -> "Constant: ${expr2.number}"
        is Expr.Sum -> "Sum: ${expr2.e1} + ${expr2.e2}"
        Expr.NotANumber -> "Not a number"
    }

    println(result)
}

Ví dụ cách dùng của data class và sealed class trong Kotlin

Hàm mở rộng (Extension Function) trong Kotlin

Extension function là một tính năng rất hữu ích, mạnh mẽ mà Kotlin cung cấp.

Tính năng Extension function của Kotlin hỗ trợ lập trình viên mở rộng logic của một Class và tái sử dụng chúng hiệu quả mà không cần phải kế thừa class đó.

Điểm giới hạn của Extension function là nó không thể truy cập vào các biến private của Class được. Vì bản chất của Extension function là một static function, được viết gọn lại cho chúng ta dễ sử dụng và Debug.

fun String.countVowels(): Int {
    var count = 0
    for (char in this) {
        if (char in "aeiouAEIOU") {
            count++
        }
    }
    return count
}

fun main() {
    val word = "Hello"
    println("The word '$word' has ${word.countVowels()} vowel(s).")
}

Cách khai báo và sử dụng Extension Function – Android Mastery

Scope Function

Scope Function là 1 dạng của Extension function, hỗ trợ các phương thức rút gọn khi thao tác lên 1 Kotlin Object.

data class Person(var name: String, var age: Int = 0, var city: String = "")
fun main() {
    val person = Person("John")
    println("Before update: Hello, $person")
    person.apply {
        age = 30
        city = "New York"
    }.apply {
        name = "Alice"
    } // lưu ý: apply trả về chính receiver object
    println("After update: Hello, $person")
}

Cách sử dụng apply trong Kotlin – Android Mastery

fun main() {
    val numbers = mutableListOf("one", "two", "three")
    numbers.also {
        it.add("four")
        println("The list elements before adding new one: $it")
    }.add("five")
    // Lưu ý: also() nhận vào chính receiver và trả về receiver object
    // Lưu ý: add() trả về Unit
    println("The list elements after adding new one: $numbers")
}

Cách sử dụng also trong Kotlin – Android Mastery

fun main() {
    val listWithNulls: List<String?> = listOf("Kotlin", null)
    for (item in listWithNulls) {
        val res = item?.let {
            println(it)
            "Printed item"
        } ?: "Null item"
        // Lưu ý: let trả về statement cuối cùng trong block
        println("Result: $res")
    }
}

Cách sử dụng let trong Kotlin – Android Mastery

Hiểu và dùng lateinit var , val by lazy

lateinit là từ khóa của Kotlin để thông báo với compiler rằng biến được khai báo với tiền tố lateinit sẽ được khởi tạo giá trị vào 1 thời điểm khác trong chương trình.

Các biến được khởi tạo bởi lateinit sẽ có dạng mutable (tức là phải được khai báo với từ khóa var ) và là 1 biến NonNullable .

Trường hợp Lập trình viên cố tình khai báo biến lateinit với khai báo Immutable hoặc với một Nullable type, trình biên dịch sẽ văng lỗi.

Trường hợp logic truy cập vào 1 biến lateinit chưa được khởi tạo, chương trình lúc này cũng sẽ văng lỗi. Chính vì điều này chúng ta cần thực sự hiểu luồng chạy của chương trình và sử dụng lateinit một cách thông minh, hiệu quả.

class User {
    lateinit var address: String
    fun setAddress(address: String) {
        this.address = address
    }
    fun printAddress() {
        if(::address.isInitialized) {
            println(address)
        } else {
            println("Address is not initialized yet.")
        }
    }
}

fun main() {
    val user = User()
    user.printAddress() // Prints: Address is not initialized yet.
    user.setAddress("1 Le Duan St")
    user.printAddress() // Prints: 123 Main St
}

Cách sử dụng lateinit

by lazy là một từ khóa khác trong Kotlin. Cụm từ khóa này thông báo cho trình biên dịch hiểu rằng biến được khai báo với by lazy chưa được khởi tạo giá trị lúc chương trình khởi chạy, thay vào đó giá trị của biến sẽ được khởi tạo ở lần truy cập đầu tiên đến biến đó.

Biến được khai báo bởi by lazy có thể là NonNullable, hoặc cũng có thể là Nullable

Tuy nhiên, by lazy phải là một Immutable , điều đó đồng nghĩa suốt vòng đời của biến chỉ mang 1 giá trị duy nhất, chính là giá trị được khởi tạo ở lần truy cập đầu tiên.

class Person {
    val name: String by lazy {
        println("Initializing name...")
        "Dan Tech 0xFF"
    }
}

fun main() {
    val person = Person()
    println(person.name) // This will print "Initializing name..." then "Dan Tech 0xFF"
}

Cách sử dụng val by lazy