Chuyển đến nội dung chính

Null Safety – Kiểm tra biến null an toàn trong Kotlin

Non-null types – Kiểu dữ liệu không thể null và Nullable types – Kiểu dữ liệu có thể null

Non-null types – Kiểu dữ liệu không thể null


Ta đã biết cách khai báo biến kèm theo giá trị khởi tạo:
Giờ ta thử gán cho biến name ở trên giá trị null xem sao:
Ta sẽ nhận đc ngay 1 thông báo lỗi Null cannot be a value of a non-null type String. Tức là giá trị null không thể được gán cho 1 biến có kiểu non-null type String. Ở bài trước, mình đã trình bày về các kiểu dữ liệu cơ bản. Tuy nhiên các kiểu dữ liệu đó đều là các kiểu non-null type, có nghĩa là không chấp nhận giá trị null. Ok, rắc rối thật đấy, không cho ta gán giá trị null thì ta thử không gán giá trị gì xem nào 😀
Giờ thì lại nhận đc thông báo thế này: variable ‘name’ must be initialized, tức là biến name phải được gán giá trị.
Vậy là bằng mọi giá, Kotlin ngăn cản ta định nghĩa 1 biến với giá trị null. Điều này có vẻ bất tiện nhưng thực ra rất an toàn, bởi khi ta không có biến null, đồng nghĩa với việc sẽ không dính vào lỗi NullPointerException đáng ghét. 1 tính năng rất cool mà Java không có đúng ko.
Nhưng chờ đã, trong thực tế, đâu phải mọi thứ đều nhất thiết phải có giá trị (khác null) đúng không. Đôi khi vẫn có những biến phải gán cho giá trị null (để giải phóng bộ nhớ chẳng hạn), hoặc những biến không phải trong trường hợp nào cũng truy xuất đến, chúng không nhất thiết phải có giá trị. Vậy để gán giá trị null cho 1 biến ta làm thế nào? Khi đó ta sẽ cần đên Nullable types – Kiểu dữ liệu có thể null.

Nullable types – Kiểu dữ liệu có thể null

Ta khai báo như sau:
Ta đã thêm 1 dấu ? vào sau kiểu dữ liệu String. Điều đó tức là biến name vẫn có kiểu là String, nhưng lúc này nó đã được phép mang giá trị null. Và lúc này trình biên dịch không còn báo lỗi nữa. Ta chạy chương trình và thu được kết quả  name = null hiển thị ở console. Và String? chính là 1 Nullable type, tức là các biến có kiểu này được phép mang giá trị null.
Vậy đúc kết lại, để khai báo các biến có thể mang giá trị null, ta dùng các kiểu dữ liệu Nullable type với cú pháp:

Safe call – Lời gọi an toàn

Đối với biến được khai báo với kiểu  Nullable type, khi truy xuất đến chúng, ta cần phải sử dụng Safe call – Lời gọi an toàn để đảm bảo chương trình ko xảy ra lỗi. Ví dụ ta muốn lấy độ dài của chuỗi name bên trên:
Ký tự ? được dùng để kiểm tra biến name có null hay không. Nếu name có giá trị,  ta lấy được giá trị của name.length và gán vào biến lengthOfName. Ngược lại, name.length sẽ không được truy xuất đến và biến lengthOfName sẽ có giá trị null. Lời gọi đến name?.length bên trên gọi là 1 safe call (lời gọi an toàn) vì nó sẽ không bao giờ gây lỗi NullPointerException, dù cho biến name có mang giá trị null. Kết quả của đoạn code trên sẽ là:
length = null
Thử gán name = “Nam” và chạy chương trình:
Ta sẽ thu được kết quả: length = 3
Nếu bỏ dấu ? trong lời gọi đến name?.length, trình biến dịch sẽ báo lỗi: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String. Tức là đối với các kiểu dữ liệu nullable (cho phép null), ta chỉ có thể dùng safe call như mình giới thiệu bên trên, hoặc sử dụng ký hiệu !! 
Vậy !! là cái gì? 

Toán tử !!

Nếu bạn chắc chắn biến name là khác null, có thể dùng !! để thay cho ?. Khi dùng !! thì dù cho name có null hay không, lời gọi đến name.length vẫn sẽ được gọi. Ta sẽ thử:
Kết quả: Length = 3
Nhưng khi name bị null thì sao:
Lúc này ta sẽ nhận được thông báo: Exception in thread “main” kotlin.KotlinNullPointerException. Đây chính là điều ta muốn tránh.
Mình không khuyến khích sử dụng !! vì nếu ở ví dụ trên, name mang giá trị null, ngoại lệ NullPointerException sẽ bị văng ra. Đôi khi ta chắc chắn 1 biến là not null nhưng vì lý do nào đó nó bị mang giá trị null, khi đó sử dụng !! sẽ rất nguy hiểm.

Thêm 1 cách để kiểm tra biến null an toàn

Như ở trên mình đã dùng ?.let để xác định xem biến name có null hay không, nếu ko null thì các câu lệnh trong khối lệnh {} mới được thực hiện. Và trong khối lệnh ta không cần phải thêm ký tự safe call (?) hay null-aserted (!!) để truy xuất đến giá trị name.length trong đối tượng name. Đơn giản vì nó đã được chứng nhận là an toàn sau từ khoá let.

Toán tử Elvis

Khi ta có 1 đối tượng str có thể mang giá trị null. Ta có thể sử dụng toán tử Elvis để kiểm tra giá trị của nó. Cách sử dụng như sau:
Câu lệnh trên có ý nghĩa là: Nếu biểu thức bên trái dấu ?: (trong trường hợp này là str?.length) khác null, thì biến length sẽ được gán giá trị của str?.length, ngược lại, biểu thức bên trái dấu ?: mang giá trị null, biến length sẽ được gán giá trị của biểu thức bên phải dấu ? (trong trường hợp này là -1). Chỉ đơn giản là vậy.

Tổng kết

Như vậy trong bài này mình đã giới thiệu với các bạn cách sử dụng safe call (lời gọi an toàn) đối với các đối tượng có kiểu nullable-type. Việc làm kiểm tra biến null này sẽ giúp các bạn giảm thiểu rất nhiều nguy cơ bị dính ngoại lệ NullPointerException, cũng tức là giảm tỉ lệ bị crash app khi bạn phát triển ứng dụng Android sau này.

Nhận xét

Bài đăng phổ biến từ blog này

Kích thước icon cho app Android và công cụ tạo icon của Google

Để hiển thị chuẩn theo các size màn hình thì chúng ta sẽ theo các kích thước sau: 36 × 36 (ldpi) – Low 48 × 48 (mdpi) – Medium 72 × 72 (hdpi) – High 96 × 96 (x-hdpi) – x-high 144 × 144 (xx-hdpi) 192 × 192 (xxx-hdpi) 512 × 512 (Google Play store) -> Kích thước này để làm ảnh demo cho App khi upload lên store. Khi tạo icon launcher cho app nếu tạo bằng các  Launcher icon generator  cửa Google thì khi cài vào điện thoại nó sẽ bé hơn so với các app khác vì google tự động cho thêm padding vào icon. Tránh điều này thì nên tự thiết kế bằng Photoshop sau đó dùng  cái này  để tạo thì sẽ to và đẹp hơn, nó tạo nhanh và đủ các kích thước chuẩn như bên trên kia. Nếu bạn muốn bo góc thì cũng làm bo góc ở trong photoshop trước sau đó mới dùng công cụ bên trên. Kiến thức liên quan đến đơn vị đo trong Android: pixel có thể hiểu là số điểm ảnh có trong 1 dot có hình vuông vì là ảnh bitmap mà. Ảnh đen trắng binary image thì 1 dot = 1 px = 1 bit (chỉ có trạng thá...

Get You Last known Location & Current Location using FusedLocationProviderClient

NOVEMBER 30, 2017 Get You Last known Location & Current Location using FusedLocationProviderClient        I would like to cover very basic and simple example of retreiving last known location & Current Location  using Fused location API.  I have written many example for fused location API in my previous posts but in this post i will show how to get retrieve the location  without implementing Google Api Client . All these magics happen after the release of version  11.0.0 of Google Play services SDK. FusedLocationProviderApi is Deprecated We have previously used following way to retrieve the last known location. mLastLocation  =  LocationServices. FusedLocationApi . getLastLocation ( mGoogleApiClient ) ; We no need to define LocationServices. FusedLocationApi  anymore. it is deprecated. It will be removed in the future release. Instead You can use LocationServi...

Cấu trúc cơ bản layout trong Flutter