Hello World và kiến thức cơ bản
Chương trình Kotlin bắt đầu từ hàm main cấp cao nhất, không cần lớp nào bao ngoài.
| Cú pháp | Ý nghĩa |
|---|
fun main() { println("Hello") } | Điểm bắt đầu chương trình |
println("text") | In một dòng ra đầu ra chuẩn |
print("text") | In không xuống dòng ở cuối |
// comment | Chú thích một dòng |
/* comment */ | Chú thích nhiều dòng |
val input = readLine() | Đọc một dòng từ stdin (kiểu nullable String?) |
val line = readln() | Đọc một dòng từ stdin (không null, Kotlin 1.6+) |
Biến (val / var) và kiểu dữ liệu
Ưu tiên val; chỉ dùng var khi giá trị buộc phải thay đổi.
| Cú pháp | Ý nghĩa |
|---|
val name = "Ada" | Biến chỉ đọc, kiểu được suy luận là String |
var count = 0 | Biến thay đổi được |
val age: Int = 30 | Khai báo kiểu tường minh |
Int, Long, Double, Float | Kiểu số (42, 42L, 3.14, 3.14f) |
Boolean, Char, String | true/false, 'a', "text" |
val big = 1_000_000 | Dấu gạch dưới giúp số dễ đọc hơn |
"3".toInt(), "2.5".toDouble() | Chuyển chuỗi thành số |
42.toString() | Chuyển số thành chuỗi |
const val MAX = 10 | Hằng số lúc biên dịch (ở cấp cao nhất hoặc trong một object) |
Chuỗi và string template
String template thay cho việc nối chuỗi ở hầu hết mọi chỗ.
| Cú pháp | Ý nghĩa |
|---|
"Hi, $name" | Chèn biến vào chuỗi |
"Total: ${price * qty}" | Chèn biểu thức |
s.length | Số ký tự |
s.uppercase(), s.lowercase() | Đổi chữ hoa / chữ thường |
s.trim() | Xóa khoảng trắng ở đầu và cuối |
s.contains("x"), s.startsWith("a") | Tìm trong chuỗi |
s.substring(0, 3) | Cắt theo khoảng chỉ số |
s.split(",") | Tách thành một List<String> |
s[0] | Ký tự tại một chỉ số |
"""raw text""" | Chuỗi thô nhiều dòng, không cần escape |
"%.2f".format(3.14159) | Đầu ra có định dạng (3.14) |
Null safety
Mặc định một kiểu không được null; thêm ? để cho phép null, và trình biên dịch sẽ buộc bạn xử lý trường hợp đó.
| Cú pháp | Ý nghĩa |
|---|
var s: String? = null | Kiểu nullable |
s?.length | Gọi an toàn: trả về null nếu s là null |
s?.length ?: 0 | Toán tử Elvis: giá trị dự phòng khi gặp null |
s!!.length | Khẳng định không null: ném lỗi nếu s là null |
if (s != null) s.length | Smart cast sang kiểu không null bên trong phép kiểm tra |
s?.let { println(it) } | Chỉ chạy khối lệnh khi không phải null |
val n = s?.toIntOrNull() | Chuyển đổi, hoặc trả về null nếu dữ liệu sai |
lateinit var x: String | Biến var không null, khởi tạo sau |
Toán tử
| Toán tử | Ý nghĩa |
|---|
+ - * / % | Số học (/ giữa hai Int là phép chia lấy phần nguyên) |
+= -= *= /= %= | Gán kết hợp |
++ -- | Tăng / giảm 1 |
== != | So sánh bằng về cấu trúc (gọi equals) |
=== !== | So sánh bằng về tham chiếu (cùng một đối tượng) |
< > <= >= | So sánh |
&& || ! | Logic and / or / not |
a in 1..10 | Kiểm tra thuộc range hoặc collection |
x as Int, x as? Int | Ép kiểu / ép kiểu an toàn (null nếu thất bại) |
x is String | Kiểm tra kiểu (tự smart cast nếu đúng) |
Luồng điều khiển (if / when)
if và when là biểu thức, nghĩa là chúng trả về một giá trị.
| Cú pháp | Ý nghĩa |
|---|
if (a > b) x else y | if dùng như biểu thức (Kotlin không có toán tử ba ngôi ?:) |
if (c) { ... } else if (d) { ... } else { ... } | Chuỗi nhánh điều kiện |
when (x) { 1 -> "one"; 2 -> "two"; else -> "other" } | So khớp một giá trị |
when (x) { 1, 2 -> "low" } | Nhiều giá trị trong một nhánh |
when (x) { in 1..9 -> "digit" } | So khớp một range |
when (x) { is String -> x.length } | So khớp kiểu (kèm smart cast) |
when { x < 0 -> "neg"; x == 0 -> "zero"; else -> "pos" } | when không có đối tượng so khớp, giống if/else if |
val label = when (x) { ... } | when dùng như biểu thức (cần có else) |
Vòng lặp và range
| Cú pháp | Ý nghĩa |
|---|
for (i in 1..5) | Range từ 1 đến 5 (bao gồm 5) |
for (i in 1 until 5) | Từ 1 đến 4 (không bao gồm giá trị cuối) |
for (i in 0..<5) | Tương tự, cú pháp range mở (Kotlin 1.9+) |
for (i in 10 downTo 1 step 2) | Đếm ngược theo bước nhảy |
for (item in list) | Duyệt một collection |
for ((i, item) in list.withIndex()) | Lấy cả chỉ số lẫn phần tử |
for (ch in "abc") | Duyệt từng ký tự của chuỗi |
while (cond) { ... } | Lặp khi điều kiện còn đúng |
do { ... } while (cond) | Chạy ít nhất một lần |
break, continue | Thoát vòng lặp / bỏ qua sang lần lặp tiếp theo |
repeat(3) { println(it) } | Chạy một khối lệnh n lần |
Hàm
| Cú pháp | Ý nghĩa |
|---|
fun add(a: Int, b: Int): Int { return a + b } | Khai báo hàm |
fun add(a: Int, b: Int) = a + b | Hàm một biểu thức, kiểu trả về được suy luận |
fun greet(name: String = "world") | Giá trị mặc định của tham số |
greet(name = "Ada") | Đối số có tên |
fun log(vararg items: String) | Số lượng đối số tùy ý |
fun say(): Unit | Không có giá trị trả về (Unit có thể bỏ qua) |
val square = { x: Int -> x * x } | Lambda lưu trong biến |
fun String.shout() = uppercase() + "!" | Hàm mở rộng (extension function) |
fun apply(f: (Int) -> Int) = f(2) | Hàm làm tham số |
list.map { it * 2 } | Trailing lambda, it là tham số duy nhất |
List
listOf chỉ đọc; mutableListOf thay đổi được.
| Cú pháp | Ý nghĩa |
|---|
val nums = listOf(1, 2, 3) | List chỉ đọc |
val items = mutableListOf("a") | List thay đổi được |
nums[0], nums.first(), nums.last() | Truy cập phần tử |
nums.getOrNull(9) | Truy cập an toàn, null nếu vượt phạm vi |
items.add("b"), items.remove("a") | Thêm / xóa |
items[0] = "z" | Thay thế theo chỉ số |
nums.size, nums.isEmpty() | Kích thước và kiểm tra rỗng |
x in nums, nums.contains(x) | Kiểm tra phần tử có trong list |
nums.indexOf(2) | Vị trí của phần tử, -1 nếu không có |
nums.subList(0, 2) | Cắt list (không bao gồm vị trí cuối) |
nums.take(2), nums.drop(1) | Lấy n phần tử đầu / bỏ n phần tử đầu |
nums.sorted(), nums.reversed() | List mới đã sắp xếp / đảo ngược |
nums.sum(), nums.average(), nums.maxOrNull() | Hàm tổng hợp |
nums.joinToString(", ") | Nối thành một chuỗi |
Pair(1, "a"), 1 to "a", Triple(1, 2, 3) | Bộ giá trị nhỏ cố định |
Map và set
| Cú pháp | Ý nghĩa |
|---|
val m = mapOf("a" to 1, "b" to 2) | Map chỉ đọc |
val mm = mutableMapOf<String, Int>() | Map thay đổi được |
m["a"] | Tra cứu (null nếu không có) |
m.getOrDefault("z", 0) | Tra cứu kèm giá trị dự phòng |
mm["c"] = 3 | Thêm hoặc cập nhật |
for ((k, v) in m) | Duyệt các cặp khóa và giá trị bằng destructuring |
m.keys, m.values | Tập khóa / tập giá trị |
"a" in m | Kiểm tra khóa có tồn tại |
val s = setOf(1, 2, 2) | Set các giá trị không trùng lặp ({1, 2}) |
mutableSetOf<Int>() | Set thay đổi được |
Thao tác trên collection (lambda)
| Cú pháp | Ý nghĩa |
|---|
list.map { it * 2 } | Biến đổi từng phần tử |
list.filter { it > 2 } | Giữ các phần tử thỏa điều kiện |
list.forEach { println(it) } | Xử lý từng phần tử |
list.any { it > 2 }, list.all { it > 0 } | Có phần tử nào / mọi phần tử đều thỏa điều kiện |
list.count { it % 2 == 0 } | Đếm số phần tử thỏa điều kiện |
list.find { it > 2 } | Phần tử đầu tiên thỏa điều kiện hoặc null |
list.sortedBy { it.length } | Sắp xếp theo khóa |
list.groupBy { it.first() } | Nhóm thành một Map |
list.distinct() | Loại bỏ phần tử trùng |
list.fold(0) { acc, x -> acc + x } | Gộp giá trị từ một giá trị ban đầu |
list.zip(other) | Ghép cặp hai list |
list.flatMap { it.toList() } | Map rồi làm phẳng |
Lớp và data class
| Cú pháp | Ý nghĩa |
|---|
class User(val name: String, var age: Int) | Lớp có hàm khởi tạo chính và thuộc tính |
val u = User("Ada", 36) | Tạo instance (không cần new) |
u.name, u.age = 37 | Đọc / ghi thuộc tính |
data class Point(val x: Int, val y: Int) | Có sẵn equals, hashCode, toString, copy |
p.copy(y = 5) | Sao chép và đổi một vài thuộc tính |
val (x, y) = p | Khai báo destructuring |
open class Base, class Sub : Base() | Kế thừa (mặc định lớp là final) |
override fun toString() = "..." | Ghi đè một thành viên |
object Config { val debug = true } | Singleton |
companion object { fun create() = User("", 0) } | Thành viên kiểu static |
enum class Color { RED, GREEN } | Enum |
sealed class Result | Cây lớp giới hạn, when kiểm tra đủ mọi trường hợp |
interface Shape { fun area(): Double } | Interface |
Xử lý lỗi
| Cú pháp | Ý nghĩa |
|---|
try { ... } catch (e: Exception) { ... } | Bắt ngoại lệ |
try { ... } finally { ... } | Luôn chạy phần dọn dẹp |
val n = try { s.toInt() } catch (e: NumberFormatException) { 0 } | try dùng như biểu thức |
throw IllegalArgumentException("bad") | Ném ngoại lệ |
require(x > 0) { "x must be positive" } | Kiểm tra đối số (ném IllegalArgumentException) |
check(ready) { "not ready" } | Kiểm tra trạng thái (ném IllegalStateException) |
s.toIntOrNull() | Trả về null thay vì ném lỗi |
runCatching { risky() }.getOrDefault(0) | Bọc lời gọi trong một Result |
Scope function
Năm hàm nhỏ giúp làm việc với một đối tượng bên trong một khối lệnh.
| Cú pháp | Ý nghĩa |
|---|
x.let { it + 1 } | it là đối tượng, trả về kết quả của khối lệnh |
x.run { this + 1 } | this là đối tượng, trả về kết quả của khối lệnh |
x.apply { field = 1 } | this là đối tượng, trả về chính đối tượng |
x.also { println(it) } | it là đối tượng, trả về chính đối tượng |
with(x) { field } | Không phải hàm mở rộng; this là x, trả về kết quả của khối lệnh |
x?.let { ... } | Cách kiểm tra null rồi dùng giá trị chuẩn Kotlin |
Mọi cú pháp Kotlin bạn hay dùng, gói gọn trong một trang. Cheat sheet Kotlin này là bảng tra cứu nhanh cho ngôn ngữ đứng sau Android và phần lớn hệ sinh thái JVM hiện đại: khai báo biến, xử lý null an toàn, rẽ nhánh với when, lặp qua range, viết hàm, và làm việc với list và map.
Mọi thứ ở đây đều là Kotlin chuẩn, chạy được trên JVM, Android lẫn Kotlin Multiplatform. Sao chép đoạn bạn cần, hoặc thử ngay trong playground Kotlin: dán đoạn code, nhấn Chạy và xem đầu ra ngay trên trình duyệt.