Thứ Ba, 31 tháng 10, 2017

Kotlin cơ bản: Function (tiếp)


Top - Level Function:
Là Function định nghĩa ngoài Class, Object, Interface. Function loại này có thể gọi trực tiếp luôn mà không cần tạo đối tượng.
Nếu ai đã từng code java thì top level function có thể hiểu là thay thế cho các static method.
ví dụ về top-level function:
package com.shine2share

fun printName(name: String): String {
    return name
}

Để sử dụng top level function trong package khác thì ta chỉ việc import nó là ok
package com.share2study

import com.shine2share.printName

fun myFun(): String {
    return printName("Dycky")
}

--> import xong, ta gọi trực tiếp hàm luôn

Lambda Expression in Kotlin
Hay còn gọi là Function Literal

- phải có cặp ngoặc nhọn {}
- ko có fun keyword
- ko có bất kỳ 1 access modifier nào ( private, public, protected)
- nó là ẩn danh (anonymous) có nghĩa là ko có tên function
- ko có kiểu trả về
- parameters ko đc bao bọc bởi cặp ( )

--> gán lambda expression với 1 biến và thực thi nó.

ví dụ 1: ko param
// lambda expression with no param
val xinChao = {println("Xin chao! Toi la Kotlin Dev.")}
fun main(args: Array<String>) {
    xinChao()
}

ví dụ 2: 1 param
// lambda expression with 1 param
val xinChao = {name: String -> println("Xin chao! $name la Kotlin Dev.")}
fun main(args: Array<String>) {
    xinChao("Ducky")
}

ví dụ 3: 2 param
val calSum = {num1: Int, num2: Int -> println("Sum of num1 and num2 is: " + (num1+num2))}
fun main(args: Array<String>) {
    calSum(1,2)
}


Lambda expression có thể làm param cho Function
fun main(args: Array<String>) {
    println(stringList.last()) // "Hola"    println(stringList.last({ s: String -> s.length == 8})) // "Xin chao"}

val stringList: List<String> = listOf("Hello", "Xin chao", "Hola")

Có thể bỏ dấu ngoặc ( ) nếu tham số truyền vào là lambda expression
println(stringList.last{ s: String -> s.length == 8}) // "Xin chao"

it keyword: tạo ra tự động bởi compiler - Kotlin sẽ tự hiểu "it" là stringList hiện tại.
fun main(args: Array<String>) {
    println(stringList.last{ it.length == 8}) // "Xin chao"}

val stringList: List<String> = listOf("Hello", "Xin chao", "Hola")

Local return in lambda expression
xét đoạn code sau
fun main(args: Array<String>) {
    printName()
}

fun printName() {
    val intList = listOf(1, 2, 3, 4, 5)
    intList.forEach {        if (it % 2 == 0) {
            return        }
    }    println("Ket thuc ham printName()")
}

dòng lệnh
println("Ket thuc ham printName()")
sẽ ko in ra theo mong muốn.
Để fix lỗi trên ta chỉ cần thêm 1 nhãn (hoặc tag name) vào sau return
intList.forEach {    if (it % 2 == 0) {
        return@forEach    }
}

bạn cũng có thể tự định nghĩa nhãn cho riêng mình
fun printName() {
    val intList = listOf(1, 2, 3, 4, 5)
    intList.forEach myLabel@{        if (it % 2 == 0) {
            return@myLabel        }
    }    println("Ket thuc ham printName()")
}

Member Function
là loại function định nghĩa trong class, object hay interface.
ví dụ:
class Circle {
    fun calArea(radius: Double): Double {
        return Math.PI * Math.pow(radius, 2.0)
    }
}

Cách thức gọi hàm như sau
fun main(args: Array<String>) {
    val circle = Circle()
    println("Dien tich hinh tron la: " + circle.calArea(3.0))
}

Anonymous Function
- ko có tên
- có fun keyword
- có thân hàm (body)
























Thứ Hai, 30 tháng 10, 2017

Kotlin cơ bản: Function


Function - khai báo trong Kotlin với từ khóa fun.
ví dụ:

fun sayHello(name: String) : String {
        return "Hello " + name
}

hoặc dùng ký hiệu $ để lấy giá trị của name như sau:
fun sayHello(name: String) : String {
        return "Hello $name"}

Function trên nhận 1 tham số truyền vào là name, kiểu String.
Kiểu trả về của function cũng là String.

Gọi hàm:

fun main(args: Array<String>) {
        val result: String = sayHello("Viet nam")
        println(result)
    }

Trong java hay c++ nếu function không trả về gì thì dùng từ khóa void. Nhưng trong Kotlin thì dùng từ khóa Unit

ví dụ:
fun print(name: String): Unit {
    println(name)
}

Bỏ qua từ khóa Unit thì chương trình vẫn chạy bình thường.

Biến hàm thành biểu thức trong Kotlin:
ví dụ:
fun getArea(width: Long, height: Long): Long {
    return width*height
} 

hàm trên chúng ta có thể viết lại như sau:
fun getArea(width: Long, height: Long) = width*height

có thể thêm kiểu trả về của function nếu bạn muốn
fun getArea(width: Long, height: Long): Long = width*height

Trong Kotlin khi gọi hàm có nhiều hơn 1 tham số truyền vào, ta ko nhất thiết phải truyền các tham số theo thứ tự bằng cách sử dụng tên của tham số.
ví dụ:
getArea(height = 14, width = 12)

hàm getArea theo định nghĩa thì width là tham số 1, height là tham số 2. Nhưng bằng cách chỉ định tên của tham số thì vấn đề thứ tự tham số truyền vào không quan trọng nữa.

Khi định nghĩa 1 hàm có tham số truyền vào, chúng ta có thể gán giá trị mặc định cho tham số:
fun getArea(width: Long, height: Long = 10): Long = width*height 

ta thấy tham số thứ 2 height được gán giá trị mặc định là 10.
nên khi gọi hàm, nếu ta ko truyền vào giá trị cho tham số height thì Kotlin sẽ lấy giá trị mặc đinh
getArea(12)

nếu trường hợp bạn truyền tham số đầy đủ thì Kotlin sẽ tính theo giá trị bạn truyền vào.

Trong java thì ko có khái niệm giá trị tham số truyền vào có giá trị mặc định như trên, nên nếu muốn khi trong dự án mà dùng cả Kotlin và Java thì ta thêm chú thích (annotation) sau cho hàm:

@JvmOverloadsfun getArea(width: Long, height: Long = 10): Long = width*height

như vậy khi biên dịch thì trình biên dịch sẽ sinh ra thêm 1 hàm overload (không có tham số mặc đinh)
mã java sinh ra thêm khi biên dịch nếu thêm @JvmOverloads
long getArea(long width);

Hàm không giới hạn tham số truyền vao
ta thêm từ khóa vararg trước tên tham số truyền vào
fun sayHello(vararg names: String) {
    for(name in names) {
        println("Hello $name")
    }
}

khi gọi hàm, truyền vào nhiêu tham số thì sẽ in ra mấy nhiêu giá trị name
sayHello("xin chao", "hello", "hola")

Hàm trả về 2 giá trị
ta thêm từ khóa Pair trong kiểu trả về của hàm
fun returnTwoValue(id: Int): Pair<Int?, Int?> {

    val values1: Map<Int, Int> = mapOf(1 to 100, 2 to 200, 3 to 300)
    val values2: Map<Int, Int> = mapOf(1 to 1000, 2 to 2000, 3 to 3000)

    val value1 = values1[id]
    val value2 = values2[id]
    return Pair(value1, value2)
}

2 giá trị trả về có thể khác kiểu
fun returnTwoValue(id: Int): Pair<Int?, String?> {

    val values1: Map<Int, Int> = mapOf(1 to 1, 2 to 2)
    val values2: Map<Int, String> = mapOf(1 to "Hanoi", 2 to "Saigon")

    val value1 = values1[id]
    val value2 = values2[id]
    return Pair(value1, value2)
}

Lấy giá trị trả về
println(returnTwoValue(1).first)
println(returnTwoValue(1).second)

Nếu muốn trả về 3 giá trị, Kotlin hỗ trợ với từ khóa Triple
fun getNameAddressAndAge(id: Int): Triple<String?, String?, Int?> {

    val Names: Map<Int, String> = mapOf(1 to "My", 2 to "Nam")
    val Addresses: Map<Int, String> = mapOf(1 to "Hanoi", 2 to "Saigon")
    val Ages: Map<Int, Int> = mapOf(1 to 12, 2 to 22)

    return Triple(Names[id], Addresses[id], Ages[id])
}

Lấy giá trị trả về
println(getNameAddressAndAge(1).first)
println(getNameAddressAndAge(1).second)
println(getNameAddressAndAge(1).third)


Thứ Hai, 23 tháng 10, 2017

Kotlin cơ bản: Ranges và Collections

1. Ranges

Kotlin thì ko có vòng lặp for như thông thường như của java, c++

Ex: for(int i = 0; i < 10; ++i)

Để thay thế cho vòng lặp for kiểu trên, Kotlin dùng khái niệm Ranges.

Ranges là 1 cái khoảng giữa 2 giá trị, thông thường là số, 1 bắt đầu và 1 kết thúc.

Sử dụng dấu .. giữa  2 số này.

Ex1: val oneToFive = 1..5

code lặp sẽ như sau

for(number in oneToFive) {
    print(number)
}

Lưu ý là số thứ 2 (trong trường hợp trên là 5) cũng bao gồm trong Ranges (lặp đến cả số 5)

Ex2: val rangeOfChar = 'a'..'z'

for(i in rangeOfChar) {
    print(i)
}

cũng có thể viết như sau:

for(i in 'a'..'z') {
    print(i)
}

Để tạo 1 range ngoài sử dụng dấu .. ta còn có thể sử dụng phương thức rangeTo() có sẵn

Ex: val oneToFive = 1.rangeTo(5) // tương đương với 1..5

tương tự có phương thức downTo()

val five2One = 5.downTo(1)

nếu duyệt vòng lặp for thì nó sẽ in ra từ 5 tới 1

for(a in five2One)
print(a)

toán tử in trong ranges dùng để kiểm tra 1 giá trị có tồn tại trong (in) ranges hay ko


if( 1 in five2One) {
    print("1 in five2One")
}

2. Collections

Collection dùng để lưu trữ một nhóm các đối tượng liên quan nhau trong bộ nhớ.

Kotlin xây dựng 1 bộ API Collection (Interface) , khi biên dịch thì nó sẽ gọi đến các cái thằng thực thi của nó (implementation).














Kotlin cơ bản: Null, Loop, Condition

1. Null

Nếu bạn đã học và code java thì chắc hẳn bạn cũng đã từng gặp và thậm chí là gặp nhiều lần NullPointerException. Exception này xảy ra khi bạn đọc 1 thuộc tính (property) hoặc gọi 1 method của 1 object mà nó đang tham chiếu (reference) tới giá trị null.

Với Kotlin thì bạn sẽ ko cần phải lo lắng về Exception này nữa. Theo mặc định thì biến trong Kotlin sẽ ko có giá trị Null, trừ khi bạn khai báo rõ ràng nó là Null.

Như ví dụ sau sẽ ko biên dịch (compiler)


val name: String = null // will not compile

Nếu bạn cố tính muốn gán giá trị null thì thêm dấu ? sau kiểu data, như sau:


val name: String? = null // will compile
name = "Nguyen The Lam" // new value is "Nguyen The Lam"

Tương tự cho các kiểu data khác: Long? Int? Object? ...

Khi bạn cố tính gán giá trị null cho 1 biến thì bạn sẽ ko thể gọi các method, property theo cách . (chấm) thông thường nữa.

Thay vào đó, bạn dùng ?. (tổ hợp dấu chấm hỏi và dấu chấm), như sau để gọi hàm, property.


val name: String? = null
print(name?.length) // will compile and print "null"

Giá trị null mà compiler in ra ở trên là 1 string "null".

Có thể gán lại giá trị null cho 1 biến khác như sau


val name: String? = null
val len: Int? = name?.length
print(len) // will compile and print "null"

Nếu vẫn muốn tạo ra NullPointerException thì thay ?. bằng !!. (ko khuyến khích)


val name: String? = null
val len: Int? = name!!.length
print(len) // NullPointerException error

Toán tử ?: hay còn gọi là toán tử Elvis

được sử dụng để cung cấp 1 giá trị thay thế cho 1 biến nếu nó null


val fullName = null
val name: String = fullName?: "Ducky"
print(name) // will compile and print "Ducky"

Đoạn code trên, compiler sẽ gán giá trị Ducky cho biến name, vì fullName = null,
Nếu fullName khác null thì giá trị của fullName sẽ gán cho name thay vì Ducky.

2. Loop

Các vòng lặp trong Kotlin: for - while - do while

- for loop


for (value in range) {
    // Execute code
}

trong đoạn code trên: in là 1 toán tử chỉ ra rằng value (giá trị) in (trong) range (1 giải giá trị)

Ex:


for (number in 1..9) {
     print("$number ") // will print  1 2 3 4 5 6 7 8 9
}

Duyệt thông qua chỉ số mảng (Array):

Có thể dùng withIndex() function hoặc indices property

- withIndex() function


val numbers = intArrayOf(1,2,3,4,5)
for ((index, value) in numbers.withIndex()) {
    print("$index index value is $value\n")
}

thực thi đoạn code trên, giá trị in ra sẽ là:


0 index value is 1
1 index value is 2
2 index value is 3
3 index value is 4
4 index value is 5

- indices property


val numbers = intArrayOf(1,2,3,4,5)
for (index in numbers.indices) {
    print("$index index value is ${numbers[index]}\n")
}

thực thi đoạn code trên, giá trị in ra:


0 index value is 1
1 index value is 2
2 index value is 3
3 index value is 4
4 index value is 5

3. Cấu trúc điều kiện: if, if - else, when

- if - tương tự java


val check= 10
if (check % 2 == 0) {
    print("$check chia hết cho 2") // 10 chia hết cho 2
}

có thể dùng is keyword để check điều kiện if


if (number is Int) {
    print("$number is an integer")
}

- if - else


val number = 3
if (number % 2 == 0) {
    print("$number chia hết cho 2")
} else {
    print("$number ko chia hết cho 2") // 3 ko chia hết cho 2
}

Một điểm lưu ý với câu lệnh if - else trong Kotlin là:

if - else còn có thể là 1 biểu thức trong Kotlin


val number = 3
val result = if (number % 2 == 0) {
    "$number chia hết cho 2"
} else {
    "$number ko chia hết cho 2"
}
print(result) // 3 ko chia hết cho 2

Lưu ý là nếu có nhiều giá trị trong if - else thì giá trị trả về của biểu thức là giá trị cuối cùng.

Ex:


val result = if (number % 2 == 0) {
    "Divisible by 2"
    "Number is $number" // Nếu thực thi thì chỉ string này được trả về
} else {
    "Not divisible by 2"
    "Number is $number"
}

- when

when trong Kotlin là 1 sự thay thế cho swith trong java, c++

when được giới thiệu thì ngắn gọn và nhiều tính năng hơn so với swith trong java, c++

các kiểu data áp dụng cho when: By, Short, Int, String, và bất kỳ object nào


fun guessTheNumber(number: Int) {
    when (number) {
        1 -> println("number is 1")
        2 -> println("number is 2")
        3 -> println("number is 3")
        else -> println("number is neither 1, 2 or 3")
    }
}

when cũng có thể ko cần đối số (argument)


fun guessTheNumber(number: Int) {
     
    when {
        number == 1 -> println("number is 1")
        number == 2 -> println("number is 2")
        number == 3 -> println("number is 3")
        else -> println("number is neither 1, 2 or 3")
    }
}

Nếu muốn thực thi nhiều hơn 1 lệnh trong 1 nhánh (branch) thì dùng cặp { } để bao code lại.


val number = 2
when (number) {
    1 -> println("number is 1")
    2 -> {
        println("number is 2")
        println("it is an even number")
    }
    3 -> println("number is 3")
}

when trong Kotlin cũng có thể làm được như sau


val number = 2
when (number) {
    1, 2 -> println("number is either 1 or 2") // lệnh này sẽ đc thực thi. (hoặc là 1 hoặc là 2)
    3 -> println("number is 3")
}