Kotlin對比Java編程語言其優勢在哪里?
隨著計算機語言的發展,以成本為核心的驅動力,推動著經歷了匯編、C、C++、Java、Kotlin的發展,其目的在于讓開發人員更好的聚焦于業務,而不用太關注語言本身的處理。
近幾年,又開始流行更高級的語言,它們被稱之為現代編程語言,比如Rust、Go、Kotlin和TypeScript等。現代的核心原因,我認為可以總結為以下幾點:
- 入門更容易
- 類型推斷
- 空指針安全
- 內置的并發支持
- 減少模板代碼(簡潔)
- 操縱集合更容易
- 更智能的垃圾回收
以上不一定非常全,但是一定程度上概括了現代語言的特點,下面我們就基于Kotlin和Java的對比,來看下Kotlin的優勢。
new個對象
new一個對象,是我們在編程中最常用的操作之一,讓我們先看下如何在Java中new一個對象。
- List<String> list =new ArrayList<String>();
- list.add("hello world");
在Java中,我們需要定義一個變量,然后通過new關鍵字聲明一個ArrayList的示例,這樣我們就可以使用他了。
但是在Kotlin,new一個對象會更簡潔。
- var list:ArrayList<String> = ArrayList<String>()
直接省略了new關鍵字即可。
類型推斷
對于以上的Kotlin代碼,我們完全可以省略掉變量:后面的類型聲明,因為kotlin可以自己推斷出來。
- val list = ArrayList<String>()
是不是覺得更簡潔了?我們開發的效率也更高了。
空指針安全
在Java中,變量,方法的參數等都是可以為null的,但是在Kotlin中默認是不允許的,通過這種強制的限制,更好的避免空指針異常。
- var list = ArrayList<String>()
- list = null
以上代碼,在編譯期你會得到一個錯誤提示:
- Null can not be a value of a non-null type ArrayList<String>
如果我們的確需要null賦值怎么做呢?在Kotlin中需要開發者自己顯示聲明才可以。
- var list:Array<String>? = null
如上所示,在類型后加?即可。但是注意,我們不提倡這種做法,在實際的開發中,你會發現?大部分都是為了兼容Java代碼使用的。
屬性
我們通常會把數據和對數據的處理封裝到一個類中,如果類中有私有字段,我們還需要提供getter和setter方法提供訪問和修改字段的方法。
- //Person.java
- public class Person {
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
- //Main.java
- public static void main(String[] args) {
- Person p = new Person();
- p.setName("張三");
- System.out.println(p.getName());
- }
以上是我們通過Java實現的一個Person類,并且定義了name私有字段,同時提供了getter和setter方法,這樣我們才能夠使用它。
通過以上代碼,大家可以看到,我們為了實現一個name的存儲,寫了很多代碼,如果一個類存在很多字段,我們會寫更多的不必要的getter和setter方法。
現在我們看在Kotlin中如何實現上面的功能。
- //Person.kt
- class Person {
- var name:String = ""
- }
- //main.kt
- fun main(){
- val p = Person()
- p.name = "張三"
- println(p.name)
- }
是的,就是這么簡單,只需要這么幾行代碼,就可以實現和Java一樣的功能,因為Kotlin可以幫我們自動的生成getter和setter這些模板代碼,就省了我們很多事情,大大的提高了我們的開發效率,并且整個代碼也更簡潔。
這里需要注意的是,如果字段是val聲明的,那么只會生成getter方法,因為val是不可修改的,等價于Java中的final修飾符;如果字段是var的,可以同時生成getter和setter方法,這時候就可以對字段賦值了。
數據類
Kotlin的簡潔不僅僅體現在getter和setter方法上,還有數據類。一個數據類是一個數據容器,它用來存放數據。
一個好的數據類的聲明,不僅有私有的字段、getter和setter方法,還要有toString、equals和hashCode方法的實現,以便對他們進行打印、比較以及更好的儲存在map中。
還是以Person類為例,一個合格的數據類代碼如下:
- public static class Person {
- private String name;
- public Person(String name) {
- this.name = name;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Person person = (Person) o;
- return Objects.equals(name, person.name);
- }
- @Override
- public int hashCode() {
- return name != null ? name.hashCode() : 0;
- }
- @Override
- public String toString() {
- return "Person{" +
- "name='" + name + '\'' +
- '}';
- }
- }
看下我們Java的實現,需要有這么30多行代碼才能實現。如果我們使用Kotlin會是怎樣的呢?
- data class Person(val name: String) {}
只需要這么一行代碼,以上的Java功能都會實現,這里的關鍵在于一個data修飾符,是不是很酸爽。
并發
Kotlin提供了協程來實現并發,相比Java的Thread和Executor等來說,它更輕便,簡潔。我們對比下并發的基本實現。
- public static void main(String[] args) throws InterruptedException {
- new MyThread().start();
- System.out.println(Thread.currentThread().getName()+":main");
- //保證JVM存活
- Thread.sleep(1000);
- }
- private static class MyThread extends Thread{
- @Override
- public void run() {
- try {
- Thread.sleep(500);
- System.out.println(Thread.currentThread().getName()+":Thread");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
運行查看輸出,我們發現MyThread并沒有阻塞main的執行,也就是并發了。
- main:main
- Thread-0:Thread
但是要注意到,Java使用了兩個線程,一個是main,一個是Thread-0。同樣的功能,我們現在使用kotlin實現下:
- fun main(){
- runBlocking {
- launch {
- delay(500)
- println("${Thread.currentThread().name}:Thread")
- }
- println("${Thread.currentThread().name}:main")
- }
- }
相比Java來說更簡潔,而且我們看下打印的輸出:
- main:main
- main:Thread
竟然是在同一個線程上實現的并發,少了一個線程的申請開銷,效率更高,這也是kotlin提出協程的概念。如果我們不想讓它在main線程上執行,可以通過切換調度器來實現。
- launch(Dispatchers.IO)
只需要把上面的代碼的launch換成launch(Dispatchers.IO)即可,這樣調度器就給我們分配了一個IO的線程池來執行我們的代碼。如果我們使用Java來實現,要自己定義線程池,還要提交Runnable,整個代碼是非常多的。
- main:main
- DefaultDispatcher-worker-1:Thread
kotlin的協程非常強大和簡潔,通過以上的例子,不能完全展示它的特性,剩下的如協程上下文、調度器、Flow、通道等能力大家可以自己摸索。
小結
通過以上對比,我們應該可以看到作為一門現代編程語言的特點和具備的優勢,而且關于Kotlin好用的特性我們還沒有完全列舉完,比如便捷的集合操作、屬性委托、擴展函數等等。