Introduction to the Kotlin Language

Nếu:

  • Bạn là một lập trình viên Java và đã chán ngấy với cú pháp dài dòng của nó
  • Bạn là một developer và bạn muốn code ít hơn để được về sớm hơn ;))
  • Bạn là một leader và bạn đang phải viết report cho việc có bug trên live do review code quá nhiều
  • Bạn theo triết lý less code less bug

thì Kotlin có thể giúp bạn ;))

Đến với nhau vì ưu điểm
Rời xa nhau vì những hiểu lầm
Trí Xàm ;))

Vì thế sau đây mình là những ưu điểm của Kotlin so với Java và từ đó mong bạn sẽ có động lực để tìm hiểu Kotlin.

  1. JVM language
  2. Clean, compact, sugar syntax
  3. Null safety
  4. Unchecked exceptions
  5. Data classes
  6. Default values
  7. Named arguments
  8. Functional programing support
  9. Extension functions
  10. Coroutines: lightweight thread

1. JVM language

Kotlin cũng giống các ngôn ngữ như Scala, Clojure, Grovvy… đều là ngôn ngữ JVM (full list). Vì thế mà nó sẽ có được các ưu điểm sau:

  • Được build thành bytecode và chạy trên JRE (Java Runtime Environment): sử dụng lại được cơ sở hạn tầng có sẵn.
  • Sử dụng chung hệ sinh thái và thư viện của Java: là một trong những ngôn ngữ phổ biến nhất Java có một hệ sinh thái và thư viện đồ sộ của Java. Bạn sẽ không phải tốn quá nhiều thời gian để tìm hoặc viết lại các thư viện khi thay đổi ngôn ngữ.
  • Tương tác được với code Java trong cùng một module/project: bạn có một module/project đang viết bằng Java. Bạn sẽ không cần phải port lại 100% mà chỉ cần một số config build thì bạn đã có được một module/project mà được code bằng cả JavaKotlin. Các này rất thích hợp cho những module/project yêu cầu tính an toànổn định. Cá nhân người viết cũng đã tiếp nhận vài project viết bằng Java và đã chuyển sang tích hợp Kotlin được gần 2 năm rồi. Khối lượng code Kotlin chỉ chiếm 35% nhưng khối lượng logic đang xử lý thì ước lượng khoảng 70%

Mình sẽ viết một vài bài chia sẻ kinh nghiệm và chiến lượt convert từ Java sang Kotlin. Mong các bạn đón nhận!!

Update: loạt bài mình nói nè From Java to Kotlin

2. Clean, compact, sugar syntax

Để nói về việc Kotlin giúp code ngắn gọn thế nào có khi phải cần một vài bài nhưng trong chapter này mình chỉ nêu một vài đặc điểm mình cho là hay nhất. Ở đây mình xem các bạn đã rành Java rồi nên sẽ k có code Java tương ứng. Còn nếu bạn chưa rành Java thì chơi Kotlin luôn đê.

Main function
1
2
3
fun main() {
    println("Hello world!")
}
Functions
1
2
3
fun sum(a: Int, b: Int): Int {
    return a + b
}

ngắn gọn hơn

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

Kotlin hỗ trợ 2 keywords là valvar để khai báo biến. Kiểu biến nếu không khai báo tường minh sẽ lấy từ giá trị. valvar khác nhau ở chỗ val không cho phép set lại giá trị, còn var thì cho

1
2
3
4
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
String templates
1
2
3
4
5
6
7
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"
Statement as expression

Các statement như if/else, try/catch, when có thể là một expression nếu cần

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
val bigger = if (a > b) a else b
val color = when {
  relax -> GREEN
  studyTime -> YELLOW
  else -> BLUE
}
val object = try {
  gson.fromJson(json)
} catch (e: Throwable) {
  null
}
Type checks and automatic casts
1
2
3
4
5
6
fun getStringLength(obj: Any): Int? {
    if (obj !is String) return null

    // `obj` is automatically cast to `String` in this branch
    return obj.length
}
Remove new keyword
1
2
val rectangle = Rectangle(5.0, 2.0)
val triangle = Triangle(3.0, 4.0, 5.0)

3. Null safety

Chắc các bạn cũng biết Null là một lỗi thiết kế trị giá tỷ đô và để loại bỏ nó Kotlin cung cấp cho ta các công cụ rất mạnh.

Mặc định Kotlin không cho phép biến chứa giá trị null

1
2
var a: String = "abc" // Regular initialization means non-null by default
a = null // compilation error

Để cho phép biến chứa giá trị null cần khai báo tường minh:

1
2
3
var b: String? = "abc" // can be set null
b = null // ok
print(b)

Không gọi hàm với biến có thể null được

1
val l = b.length // error: variable 'b' can be null

Để gọi được cần thêm ?. khi đó kết quả có thể null.

1
val l = b?.length // l is nullable

Kiểm tra null với bl = 0 nếu b == null.

1
val l = b?.length ?: 0 // if (b == null) then l = 0 else l = b.length

Safe Casts

1
2
val aInt = a as? Int // aInt: Int?
val aIntDefault = a as? Int ?: 0 // val aInt = if (a !is Int) 0 else a as Int

4. Unchecked exceptions

Ở bài Try/Catch Explain mình cũng đã nói không thích nó. Tất nhiên không phải mình mà còn rất nhiều các bài khác:

Và thật là may mắn khi khi tất cả các Exception trong KotlinUnchecked exceptions ;))

5. Data classes

Giả sử ta cần khai báo một class User gồm 2 fields nameage với Kotlin ta chỉ cần:

1
data class User(val name: String, val age: Int)

Khi này Kotlin sẽ tự động tạo ra các method:

  • Các getter/setter
  • equals()/hashCode()
  • toString() có dạng: User(name=John, age=42)
  • copy(): copy giá trị của biến và thay đổi một hoặc nhiều fields. Sẽ nói rõ hơn ở 7. Named arguments

6. Default values

Kotlin hỗ trợ default values cho constructormethod. Mình lấy ví dụ User5. Data classes sửa lại thành

1
data class User(val name: String = "Tri Le", val age: Int = 30)

khi đó ta có thể:

1
2
val trile = User() // User(name=Tri Le, age=30)
val join = User("Join") // User(name=Join, age=30)

7. Named arguments

Tiếp tục với User6. Default values khi kết hợp với named arguments với default values ta thể:

1
2
3
val join = User(name = "Join") // User(name=Join, age=30)
val trile = User(age = 30) // User(name=Tri Le, age=30)
val mary = User(name = "Mary", age = 16) // User(name=Mary, age=16)

khi này code chúng ta rất rõ nghĩa

8. Functional programing support

Lambdas là một big change đối với Java 8Kotlin lại nâng nó lên một tầm cao mới.

Giả sử mình define một class Student như sau:

1
2
3
4
5
6
class Student(
    val name: String,
    val surname: String,
    val passing: Boolean,
    val averageGrade: Double
)

từ danh sách các Student trên mình có yêu cầu sau:

Lấy ra 10 sinh viên đã tốt nghiệp và có điểm trung bình lớn hơn 4.0
Ưu tiên cho những sinh viên điểm cao hơn 
Thứ tự được sắp xếp theo tên sinh viên (surname rồi tới name)

Với yêu cầu trên với Java ta cần implement khá nhiều. Nhưng với Kotlin ta chỉ cần 4 line ;))

1
2
3
4
students.filter { it.passing && it.averageGrade > 4.0 } // get only students who are passing and with a grade point average of greater than 4.0
    .sortedBy { it.averageGrade } // sort by the average grade
    .take(10) // take first 10 students
    .sortedWith(compareBy({ it.surname }, { it.name })) // sort students alphanumerically. The comparator compares surnames first, and if equal then it compares names

Đây là ví dụ trong bài blog này. Và nếu có thời gian mình sẽ có một bài viết chi tiết hơn nha ;))

9. Extension functions

Đây là ưu điểm mình yêu thích nhất của Kotlin vì nếu có nhu cầu viết thêm method hoặc properties ta không cần viết sửa code, rất thích hợp cho việc tích các module/lib có sẵn. Hãy nhớ rằng đây chỉ là syntactic sugar và không thật sự thay đổi class hoặc instance.

Mình giả sử muốn viết hàm checkEmpty cho String? thì ca cần:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
fun String?.checkEmpty() = this == null || this.isEmpty()

fun main() {

  val nullString: String? = null
  val emptyString = ""
  val string = "hello"
  nullString.checkEmpty() // false
  emptyString.checkEmpty() // false
  string.checkEmpty() // true

}

Tương tự ta có thể extension luôn cả propertie. Lưu ý ở đây extension propertie cần phải tính từ các thuộc tính khác của class hiện tại

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
val String?.empty
  get() = this == null || this.isEmpty()

fun main() {

  val nullString: String? = null
  val emptyString = ""
  val string = "hello"
  nullString.empty // false
  emptyString.empty // false
  string.empty // true

}

10. Coroutines: lightweight thread

Trước đây khi làm việc về mảng Network Programming mình có làm việc khá nhiều với Java thread và nhận thấy nó có những nhược điểm sau:

  • Java thread chiếm nhiều resource. Không có số liệu chính xác nhưng mỗi thread sẽ sử dụng 330KB với OS 32 bit và 1MB với OS 64 bit. Vì thế một process chỉ có thể tạo một số lượng giới hạn thread
  • Cần phải giải quyết vấn đề tranh chấp resource ảnh hưởng tới hiệu năng, độ phức tạp của project/module
  • Khó code, khó test, khó debug, khó trace
  • Deadlock

Những vấn đề trên có thể được giải quyết với Coroutines. Và chắc chắc cần phải có một loạt bài viết từ cơ bản tới nâng cao để giúp các bạn nắm vững Coroutines.

Trong khuôn khổ bài viết này mình sẽ ví dụ một case mà Java thread không làm được xem như thị phạm ;))

1
2
3
4
5
6
7
8
fun main() = runBlocking {
    repeat(100_000) { // launch a lot of coroutines
        launch {
            delay(5000L)
            print(".")
        }
    }
}

Đoạn code trên sẽ tạo ra 100K coroutines và sau 5 giây sẽ in ra dấu chấm với mỗi coroutine. Và bạn thử implement đoạn code trên với Java thread xem. Mình đảm bảo sẽ có lỗi out-of-memory

Update: loạt bài về Kotlin Coroutine

Kết: Mong với bài viết này sẽ giúp cho các bạn có cảm hứng để tìm hiểu về Kotlin. Từ đó nghiên cứu và áp dụng cho những dự án sắp tới của mình.

updatedupdated2020-11-252020-11-25
Load Comments?