Kotlin là gì? Giải đáp về Kotlin – ngôn ngữ có thể thay thế cho Java

Linh Le

Kotlin đem đến nhiều lợi ích to lớn so với Java trong môi trường máy ảo JVM và việc phát triển phần mềm trên Android, nó cũng tương tác thuận lợi với Java trong cùng dự án. Thế thì tại sao bạn không thử Kotlin?

What is Kotlin? The Java alternative explained

Kotlin là một ngôn ngữ lập trình “thực dụng” kiểu tĩnh, mã nguồn mở đa mục đích dành cho JVM và Android. Ngôn ngữ này kết hợp đặc tính lập trình hướng đối tượng và lập trình hàm (functional programming). Nó tập trung vào khả năng tương tác, độ tin cậy, tính tường minh và hỗ trợ các công cụ. Các phiên bản Kotlin dành cho JavaScript (ECMAScript 5.1) và code trên nền tảng của mình (native code, dùng LLVM) đang được hoàn thiện.

Kotlin được xây dựng từ JetBrains, công ty đứng sau IntelliJ IDEA vào năm 2010, và là mã nguồn mở từ năm 2012. Team Kotlin hiện nay có hơn 20 thành viên chính thức từ JetBrains, và dự án Kotlin trên GitHub có khoảng 100 thành viên đóng góp. JetBrains dùng Kotlin trong nhiều sản phẩm của mình bao gồm phần mềm chủ lực IntelliJ IDEA

convert java to kotlin

Thoạt nhìn, Kotlin trông như một phiên bản Java được sắp xếp hợp lý. Hãy xem màn hình chụp bên trên, đó là phần tôi chuyển code Java (bên trái) sang Kotlin một cách tự động. Chú ý rằng việc lặp lại một cách máy móc thường thấy trong việc tạo biến Java không còn nữa. Cách khai báo của Java

trong Kotlin sẽ trở thành

Có thể thấy rằng các hàm được định nghĩa với từ khóa fun, và dấu chấm phẩy không còn bắt buộc khi các dòng mới xuất hiện. Từ khóa val khai báo thuộc tính read-only hay biến cục bộ. Tương tự, từ khóa var khai báo thuộc tính có thể thay đổi hay biến cục bộ.

Tuy nhiên, Kotlin phân biệt kiểu dữ liệu mạnh mẽ hơn. Từ khóa val và var có thể được dùng chỉ khi kiểu có thể được suy luận ra. Nếu không thì bạn cần phải khai báo kiểu của dữ liệu. Việc tự suy ra kiểu dữ liệu có vẻ như đang cải thiện dần trong từng phiên bản phát hành sau của Kotlin.

Hãy xem qua việc khai báo hàm gần phía trên cùng của cả hai màn hình phía trên. Kiểu trả về của Java đứng trước mẫu đầu tiên, nhưng trong Kotlin thì nó theo sau mẫu đầu tiên, được ngăn cách bởi dấu hai chấm như trong Pascal.

Trong ví dụ này thì không rõ lắm, nhưng Kotlin đã nới lỏng yêu cầu của Java khi mà các hàm có thể là các thành tố trong lớp. Trong Kotlin, hàm có thể được khai báo ở mức cao nhất của một file, bên trong hàm khác, có thể được khai báo như một hàm thành viên (member function) trong một lớp hay đối tượng, và cũng có thể như hàm mở rộng (extension function). Các hàm mở rộng đem đến các tính năng giống với C# nhằm mở rộng một lớp cùng chức năng mới mà không phải kế thừa từ lớp hay dùng bất cứ kiểu mẫu thiết kế nào chẳng hạn như Decorator.

Với các fan của Groovy thì Kotlin có bổ sung các builder; thực tế là các buider của Kotlin có thể được kiểm tra kiểu. Kotlin hỗ trợ delegated properties (thuộc tính ủy nhiệm), có thể được dùng để thực thi các lazy properties (giá trị của property được tính toán trong lúc truy cập lần đầu tiên đến property), observable properties (lắng nghe sự thay đổi giá trị của property), vetoable properties (biến được định nghĩa khi được gán giá trị mới phải đủ điều kiện, nếu không sẽ bị từ chối) và mapped properties.

Nhiều cơ chế không đồng bộ có ở những ngôn ngữ khác có thể được thực thi vì các thư viện dùng cách viết coroutines của Kotlin, phương pháp đã được thực nghiệm với Kotlin 1.1. Nó bao gồm từ khóa async/await từ C# và ECMAScript, các channel và select từ Go và generators/yield từ C# và Python.

Lập trình chức năng trong Kotlin

Cho phép các hàm mức cao nhất chỉ là phần khởi đầu của câu chuyện lập trình hàm cho Kotlin. Ngôn ngữ này cũng hỗ trợ các hàm higher-order, các hàm ẩn danh (anonymous), hàm lambda, hàm nội tuyến (inline), hàm closure, đệ quy đuôi (tail recursion), và generics. Nói cách khác, Kotlin có tất cả các tính năng và lợi thế của một ngôn ngữ hàm. Ví dụ, hãy xem xét qua các cách viết trong Kotlin sau.

Lọc một danh sách trong Kotlin

 Để diễn đạt ngắn gọn hơn, dùng it khi chỉ có một thông số đơn trong hàm lambda:

Di chuyển ngang dọc qua một bản đồ/danh sách theo tọa độ trong Kotlin

k và v có thể là bất cứ giá trị nào.

Diễn tả một khoảng trong Kotlin

Các ví dụ bên trên cho thấy từ khóa for cũng như việc diễn tả các khoảng giá trị.

Mặc dù Kotlin là một ngôn ngữ lập trình hàm hoàn thiện, nhưng nó vẫn giữ lại hầu hết các đặc tính lập trình đối tượng của Java và xem chúng như phong cách lập trình thay thế, điều này rất tiện lợi khi chuyển đổi code Java có sẵn. Kotlin có các lớp classes có phương thức khởi tạo, nested class, inner class, và inner anonymous class, và nó có các giao diện interfaces giống như Java 8. Kotlin không có từ khóa new. Để tạo một instance trong class, gọi constructor như một hàm thông thường. Chúng ta thấy điều này trong màn hình chụp bên trên.

Kotlin có tính năng kế thừa từ một lớp cha đã được đặt tên (superclass), và tất cả các lớp của Kotlin có một lớp cha mặc định là Any, khác với lớp base trong Java là java.lang.Object. Lớp Any chứa chỉ 3 hàm đã được định nghĩa trước: equals(), hashCode() và toString().

Các lớp trong Kotlin phải được đánh dấu bằng từ khóa open nhằm cho phép các lớp khác kế thừa mình; các lớp trong Java thì ngược lại, vì chúng có thể kế thừa nếu không bị đánh dấu bằng từ khóa final. Để ghi đề một phương thức lớp cha, thì phương thức đó phải được đánh dấu open, và phương thức trong lớp con phải được đánh dấu override. Trong Kotlin, điều này chính là triết lý khiến mọi thứ tường minh hơn là phụ thuộc vào các mặc định (default).Trong trường hợp cụ thể này, tôi có thể thấy cách Kotlin đánh dấu tường minh các đối tượng trong lớp base là open cho mục đích kế thừa và các đối tượng được dẫn xuất là override có thể tránh được một số lỗi phổ biến trong Java.

Các tính năng đáng tin cậy trong Kotlin

Nói về việc tránh các lỗi phổ biến thì Kotlin được thiết kế để loại bỏ các rủi ro của việc trỏ tới kết quả null và tinh giản hóa việc xử lý các giá trị null. Nó thực hiện điều này thông qua việc không công nhận null là kiểu dữ liệu chuẩn, bổ sung thêm kiểu nullable và thiết lập các chú giải ngắn nhằm xử lý các trường hợp kiểm tra null.

Ví dụ, kiểu biến thông thường String không thể có giá trị null:

Nếu bạn cần cho phép kiểu null, ví dụ như giữ kết quả truy vấn SQL, bạn có thể khai báo kiểu null bằng cách viết thêm dấu hỏi kế kiểu dữ liệu, ví dụ String?

Mức độ tin cậy sẽ cao hơn nhiều. Bạn có thể dùng kiểu non-nullable thoải mái không cần lo lắng, nhưng nếu bạn dùng kiểu nullable với các giá trị null thì bạn phải kiểm tra các giá trị null trước khi dùng.

Nhằm tránh cú pháp dài dòng thường thấy trong việc test kiểu null, Kotlin áp dụng việc gọi có tính tin cậy, được viết dưới dạng ?..Ví dụ, b?.lenght trả về b.lenght nếu b không phải null và ngược lại, nếu b là null. Kiểu diễn đạt này là Int?.

Nói cách khác, b?.lenght là dạng ngắn gọn của if (b != null) b.length else null. Chuỗi cú pháp loại bỏ khá nhiều sự rườm rà trong logic, nhất là khi một đối tượng được đưa vào từ một chuỗi truy vấn database mà bất cứ đối tượng nào trong đó cũng có thể không thỏa yêu cầu. Ví dụ, bob?.department?.head?.name sẽ trả về tên của giám đốc bộ phận của Bob (Bob’s department head) nếu Bob, bộ phận (department), và giám đốc bộ phận (department head) đều là kiểu non-null.

Để thực hiện thao tác nhất định chỉ với các giá trị non-null, bạn có thể dùng toán tử safe call ?. Cùng với let:

Thường thì bạn sẽ cần trả về một giá trị có hiệu lực nhưng là giá trị đặc biệt từ một biểu thức nullable, thường thì để bạn có thể lưu nó vào kiểu non-nullable. Có một cú pháp đặc biệt cho ý tưởng này được gọi vui là toán tử Elvis, được viết là ?:

tương tự với:

Tương tự, Kotlin thiếu các checked exception trong Java, là những điều kiện có thể bỏ qua nhưng phải được phát hiện. Ví dụ, signature trong JDK

yêu cầu bạn bắt IOExeption mỗi khi bạn gọi phương thức append

Người thiết kế Java cho rằng đây là ý hay và nó là một lợi ích lớn với các chương trình trò chơi, miễn là các lập trình viên thực hiện những thứ hợp lý trong mệnh đề catch. Tuy nhiên thường xuyên thì trong những chương trình Java lớn, bạn thấy code mà trong đó mệnh đề bắt buộc catch không chứa gì khác ngoài một dòng ghi chú: //todo: handle this

Cái này chẳng giúp ích gì cả, và những checked exception thành ra lại là tổn thất to lớn với các chương trình lớn.

Kotlin cho Android

Cho tới tháng năm năn 2017, các ngôn ngữ lập trình hỗ trợ chính thức cho Android là Java và C++. Google thông báo chính thức hỗ trợ Kotlin cho Android tại hội nghị thường niên Google I/O 2017, và bắt đầu từ Android Studio 3.0, Kotlin được tích hợp vào bộ công cụ phát triển Android. Kotlin có thể được thêm vào các phiên bản Android Studio cũ hơn bằng plug-in.

Kotlin biên dịch ra byte code giống với Java, tương tác với các lớp Java bình thường và có cùng công cụ với Java.Vì không có chi phí gián tiếp giữa việc chuyển qua lại giữa Kotlin và Java, nên việc thêm Kotlin ngày càng nhiều vào ứng dụng Android gần đây trong Java là hoàn toàn dễ hiểu. Cũng có vài trường hợp tính tương tác giữa code Kotlin và Java thiếu linh hoạt, chẳng hạn như các thuộc tính set-only trong Java thường hiếm khi được bắt gặp và hiếm khi sửa được dễ dàng.

Pinterest chính là một minh chính quảng cáo cho các ứng dụng Androi được viết bằng Kotlin vào giai đoạn đầu, tháng 11 năm 2016, và nó cũng được đề cập nhiều tại Google I/O 2017, như một phần trong thông báo về Kotlin. Thêm nữa, team Kotlin cũng thích dẫn chứng ứng dụng Evernote, Trello, Square và Coursera cho Android

Kotlin và Java

Câu hỏi nên chọn Kotlin hay Java với các phát triển mới đã được đề cập nhiều trong cộng đồng Android kể từ thông báo tại Google I/O, mặc dù mọi người đã hỏi câu hỏi này vào tháng hai 2016, khi Kotlin 1.0 được phát hành. Câu trả lời ngắn gọn là code Kotlin đáng tin cậy và ngắn gọn hơn code Java, và các file của Kotlin và Java có thể cùng tồn tại trong ứng dụng Android, vì vậy Kotlin không chỉ hữu dụng cho các ứng dụng mới mà còn mở rộng các ứng dụng Java có sẵn.

Tranh cãi thuyết phục duy nhất mà tôi từng thấy giữa việc chọn Java thay vì Kotlin là trong trường hợp của những lập trình viên Android hoàn toàn mới. Với họ, rào cản phải vượt qua là hầu hết các tài liệu và ví dụ về Android đều viết bằng Java. Ngược lại, chuyển từ Java sang Kotlin trong Android Studio là chuyện đơn giản, chỉ cần đưa code Jave vào file Kotlin là xong.

Ngoài đối tượng trên ra thì với hầu hết mọi người đang xây dựng ứng dụng Android thì những lợi thế của Kotlin rất đáng thuyết phục. Thời gian lý tưởng cho một lập trình viên Java học Kotlin là vài giờ – một cái giá nhỏ để loại bỏ rắc rối với null, cho phép các hàm mở rộng, hỗ trợ lập trình hàm và thêm các coroutine.

Kotlin và Scala

Câu hỏi nên chọn Kotlin hay Scala không phổ biến trong cộng đồng Android lắm vì việc hỗ trợ công cụ Android cho Scala không thực sự tốt, và thư viện cho Android của Scala có xu hướng khá lớn. Ngược lại, cộng đồng Scala nhận thức được các vấn đề và tự tìm giải pháp cho mình.

Trong các môi trường khác thì tình huống lại khác.Ví dụ, Apache Spark hầu hết thường được viết bằng Scala, và các ứng dụng big data cho Spark thường viết bằng Scala.

Trong nhiều khía cạnh thì Scala và Kotlin đều cho thấy sự kết hợp của lập trình hướng đối tượng, như đã được minh họa bởi Java, với lập trình hàm. Hai ngôn ngữ có nhiều ý tưởng và ký hiệu giống nhau, chẳng hạn như khai báo không thay đổi bằng cách dùng val và khai báo có thể thay đổi thông qua var, nhưng cũng khác nhau một số khía cạnh, chẳng hạn như vị trí đặt mũi tên khi khai báo hàm lambda và khi nào thì dùng mũi tên đơn hay kép. data class của Kotlin tương ứng với case class trong Scala.

Kotlin định nghĩa các biến giá trị nullable giống với Groovy, C# và F#, hầu hết mọi người đều hiểu nó. Ngược lại Scala định nghĩa biến null bằng cách dùng Option, có vẻ như khá rủi ro đến nỗi một số tác giả có vẻ xem nó không đủ tin cậy với null.

Một thiếu sót rõ ràng của Scala là thời gian biên dịch có vẻ lâu, điều này rất rõ khi bạn build một chương trình Scala lớn từ source, chẳng hạn như kho dữ liệu Spark. Ngược lại thì Kotlin được thiết kế để biên dịch nhanh với hầu hết các kịch bản phát triển phần mềm thường xuyên nhất, và thực tế là nó thường biên dịch nhanh hơn code Java.

Tính tương tác của Kotlin với Java

Ở điểm này có thể bạn băn khoăn làm thế nào để Kotlin xử lý kết quả của các yêu cầu tương tác trong Java, khi có sự khác nhau trong xử lý null và các checked exception. Kotlin tự đưa ra một khái niệm gọi là “kiểu platform” có hành vi giống như kiểu dữ liệu trong Java, tức là nó thuộc kiểu nullable nhưng có thể tạo ra các exception trỏ tới null (null-pointer exceptions). Kotlin cũng có thể thêm lệnh vào code khi biên dịch để tránh  việc kích hoạt một exception trỏ về null thực sự. Không có ký hiệu ngôn ngữ rõ ràng nào cho kiểu platform, nhưng khi Kotlin phải báo cáo kiểu platform, chẳng hạn như thông báo lỗi, nó sẽ thêm dấu ! vào kiểu’

Trong hầu hết mọi trường hợp, việc gọi code Java từ Kotlin hoạt động theo đúng ý bạn mong muốn. Ví dụ, bất cứ khi nào các getter và setter tồn tại trong một lớp của Java thì Kotlin xem chúng như những thuộc tính có cùng tên. Tương tự, các phương thức truy cập  kiểu Boolean được xem như các thuộc tính có cùng tên với phương thức getter. Ví dụ:

Phương án này thất bại với trường hợp các thuộc tính là set-only trong Java vì không được Kotlin hỗ trợ. Nếu một lớp trong Java chỉ có setter thì nó sẽ không được xem là thuộc tính trong Kotlin.

Tính tương tác của Kotlin với Java mở rộng với cả các công cụ Java. Kotlin không có editor hay các IDE của riêng mình, nó có các plug-in cho các editor Java và IDE phổ biến, bao gồm IntelliJ IDEA, Android Studio, và Eclipse. Kotlin không có hệ thống build của riêng nó, nó sử dụng Gradle, Maven và Ant.

Tính tương tác của Kotlin với JavaScript

Bạn có thể dùng Kotlin để viết code cho các trình duyệt và Node.js. Với mục tiêu này, Kotlin được chuyển (transpiled) qua JavaScript ES5.1 thay vì được biên dịch sang byte code trong JVM.

Vì JavaScript là một ngôn ngữ động nên Kotlin dành cho JavaScript phải thêm kiểu động không có sẵn trong Kotlin cho môi trường JVM:

Kiểm tra kiểu trong Kotlin loại bỏ kiểu dynamic và để cho JavaScript  xử lý nó vào lúc runtime. Những biểu thức dùng các biến kiểu dynamic được dịch thành JavaScript khi chúng được viết ra. Một lần nữa, Kotlin chỉ để cho JavaScript biên dịch biểu thức vào runtime.

Bạn có thể gọi JavaScript từ Kotlin bằng hai cách: dùng kiểu dynamic hoặc dùng các header Kotlin được phân kiểu rõ ràng dành cho thư viện JavaScript. Để truy cập các framework phổ biến từ bên thứ ba JavaScript với API có kiểu rõ ràng, bạn có thể đổi định nghĩa TypeScript  từ kho định nghĩa kiểu DefinitelyTyped sang Kotlin bằng cách dùng công cụ ts2kt.

Bạn có thể theo code JavaScript khi nhập vào code Kotlin của mình bằng cách dùng hàm js(“…”). Bạn có thể đánh dấu khai báo package trong code Kotlin là JavaScript thuần túy với điều chỉnh external. Bạn có thể gọi code Kotlin từ JavaScript, nhưng bạn cần dùng tên đúng chuẩn.

Nhìn chung, Kotlin đem lại nhiều lợi thế so với Java khi chạy code trên JVM và cũng có thể tạo ra JavaScript và native code. So với Java, Kotlin đáng tin cậy hơn, ngắn gọn và tường minh hơn. Nó hỗ trợ lập trình hàm bên cạnh lập trình hướng đối tượng, đem đến nhiều tính năng hữu ích (hàm mở rộng, builder, coroutine, lambda,…), và mang lại độ tin cậy với null thông qua kiểu nullable và non-nullable. Hơn hết, nếu bạn đã biết về Java thì bạn sẽ không mất thời gian để tạo ra sản phẩm bằng Kotlin.

Chia sẻ bài viết ngay

Nguồn bài viết : https://www.infoworld.com