Tính năng toán tử và xử lý null trong Kotlin

Kotlin cho phép định nghĩa lại hành vi của các toán tử thông qua hàm đặc biệt có từ khóa operator. Điều này giúp code trực quan và tự nhiên hơn khi làm việc với kiểu dữ liệu tùy chỉnh.

Toán tử một ngôi

Khi sử dụng toán tử như +, -, hoặc !, Kotlin sẽ gọi tương ứng các phương thức unaryPlus(), unaryMinus(), và not().

data class Vector(val dx: Int, val dy: Int)

operator fun Vector.unaryMinus() = Vector(-dx, -dy)

val v = Vector(5, 8)
println(-v) // Kết quả: (-5, -8)

Toán tử số học và gán kết hợp

Các phép tính như cộng, trừ, nhân, chia được ánh xạ tới các hàm plus, minus, times, div. Toán tử gán kết hợp (ví dụ +=) sẽ gọi hàm dạng plusAssign.

data class StepCounter(val step: Int) {
    operator fun plus(steps: Int): StepCounter {
        return StepCounter(step + steps)
    }

    operator fun plusAssign(steps: Int) {
        this.step += steps // giả sử mutable
    }
}

Toán tử truy cập chỉ mục và gọi hàm

Bạn có thể định nghĩa cách truy cập phần tử qua [] bằng get/set, hoặc gọi đối tượng như hàm qua invoke().

class Matrix(val data: List<List<Int>>) {
    operator fun get(row: Int, col: Int): Int = data[row][col]
    operator fun set(row: Int, col: Int, value: Int) {
        data[row][col] = value
    }
}

class Greeter(val greeting: String) {
    operator fun invoke(name: String) = "$greeting, $name!"
}

val greet = Greeter("Xin chào")
println(greet("An")) // "Xin chào, An!"

Xử lý giá trị null an toàn

Kotlin phân biệt rõ ràng giữa kiểu nullable (String?) và non-null (String). Trình biên dịch ngăn chặn truy cập không an toàn vào giá trị null.

var text: String? = "Hello"
// text.length // Lỗi biên dịch

// Kiểm tra null truyền thống
if (text != null) {
    println(text.length)
}

// Toán tử an toàn `?.`
println(text?.length) // In ra 5 hoặc null

// Toán tử Elvis `?:` để cung cấp giá trị mặc định
val len = text?.length ?: 0

// Ép kiểu an toàn
val num: Int? = text as? Int

// Lọc danh sách loại bỏ null
val numbers: List<Int?> = listOf(1, null, 3)
val clean: List<Int> = numbers.filterNotNull()

So sánh và kiểm tra bằng nhau

Toán tử so sánh (<, >) gọi compareTo. Toán tử bằng (==) gọi equals với xử lý null tự động.

data class Version(val major: Int, val minor: Int) : Comparable<Version> {
    override fun compareTo(other: Version): Int {
        return when {
            major != other.major -> major - other.major
            else -> minor - other.minor
        }
    }
}

val v1 = Version(1, 2)
val v2 = Version(1, 3)
println(v1 < v2) // true

Xử lý ngoại lệ

Kotlin không bắt buộc khai báo checked exception. Câu lệnh try-catch là biểu thức, trả về giá trị từ khối try hoặc catch.

fun parseNumber(input: String): Int? {
    return try {
        input.toInt()
    } catch (e: NumberFormatException) {
        null
    }
}

val result = parseNumber("abc") ?: throw IllegalArgumentException("Invalid number")

Chú thích (Annotations)

Annotation trong Kotlin hỗ trợ nhiều vị trí áp dụng như field, getter, constructor... và có thể nhận tham số là lớp, mảng, enum...

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class Metadata(val version: String, val author: String)

@Metadata(version = "1.0", author = "DevTeam")
class DataService {
    @Inject lateinit var repository: DataRepo
}

// Áp dụng annotation lên field Java
class Example(@field:JvmField val id: Int)

Thẻ: Kotlin operator-overloading null-safety annotations exception-handling

Đăng vào ngày 18 tháng 6 lúc 00:45