Kotlin入門

小楠總發表於2017-12-21

###Kotlin簡介

####Kotlin是什麼

Kotlin是JetBrains公司開發的一門語言,一聖彼得堡附近的Kotlin島嶼來命名的。Kotlin是執行在JVM上面的一門靜態強型別語言,可以編譯成JavaScript原始碼,執行在瀏覽器上,與Java100%相容。

####Kotlin的特性

為什麼有了Java還需要有Kotlin?下面就看看Kotlin的一些特性吧:

  • 空型別安全
  • Lambda表示式
  • 擴充套件方法
  • 型別推導
  • 勝任Java能做的所有事情,使用起來比Java簡單,例如沒有句末分號

####Kotlin相關參考資料

kotlinlang.org

blog.jetbrains.com/kotlin/

github.com/JetBrains/k…

###Kotlin環境搭建

####Kotlin練習環境搭建之--Hello Word!

下面我們先用IDEA來建立一個專案,開啟IDEA,建立專案,選擇Kotlin(JVM),如下圖所示:

Kotlin建立專案.png

######Tips:如果沒有Kotlin選項,請先安裝Kotlin外掛,建立專案需要選擇lib庫。 ######Tips:首次建立專案需要Index一兩分鐘。

與Java一樣,在src目錄下面建立一個Package,建立.kt檔案:

fun main(args: Array<out String>) {
    print("Hello Word\n")
	//建立類的時候不需要new關鍵字了
    print(MyBean(1, "test bean"))
}

//Kotlin風格的資料物件
data class MyBean(var id: Int, var name: String)
複製程式碼

那麼程式就會輸出:

Hello Word
MyBean(id=1, name=test bean)
複製程式碼

####Kotlin練習環境搭建之--使用Gradle搭建環境

Gradle是一個依賴管理的工具,以前我們都是直接把jar包等原始碼直接拷貝進來的,但是這樣很麻煩。有了Gradle之後,我們就可以通過指令碼或者圖形化介面進行依賴管理了,對以後依賴庫的升級維護也很方便。

同樣用IDEA進行開發,下面我們建立一個專案,選擇Gradle、Kotlin,如下圖所示:

Gradle建立Java與Kotlin專案.png

接下來配置構件資訊,其中包括代表公司或者組織的GroupId,代表自己在公司或者組織裡面的代表自己的ArticleFactId,然後就是構件的版本:

配置構件的資訊.png

然後就是配置Gradle,這裡筆者使用自己本地的Gradle,然後選擇生成一些重要的資料夾,例如src/main/java目錄:

配置Gradle.png

專案建立好之後如下:

專案一覽.png

工具已經幫我們建立好需要的目錄了。我們下面來看一些與Gradle相關的重要檔案:

settings.gradle:是存放每個module的資訊的,其內容如下:

rootProject.name = 'KotlinDemo'
複製程式碼

build.gradle,與build相關的指令碼,其內容如下:

group 'nan.com'
version '1.0-SNAPSHOT'

buildscript {
    repositories {
        //下面的dependencies中,外掛的地址
        jcenter()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.4"
    }
}

//標識Java與Kotlin工程,存放著與編譯相關的一系列指令集
apply plugin: 'java'
apply plugin: 'kotlin'

//標識Java的版本,這裡沒有使用到
sourceCompatibility = 1.5

repositories {
    //module中的依賴的地址
    jcenter()
}

//Gradle中最重要的功能--依賴管理
dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib:1.0.4"
    testCompile group: 'junit', name: 'junit', version: '4.11'
}
複製程式碼

####使用Gradle進行依賴管理

由於Kotlin中,反射包是獨立與基礎包的,因此我們以反射這個包為例子,介紹一下使用Gradle進行依賴管理。

修改build.gradle:

//Gradle中最重要的功能--依賴管理
dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib:1.0.4"
	//增加反射依賴
    compile "org.jetbrains.kotlin:kotlin-reflect:1.0.4"
    testCompile group: 'junit', name: 'junit', version: '4.11'
}
複製程式碼

然後就可以在程式碼中進行反射操作了,例如我們拿到Person類的構造方法:

fun main(args: Array<String>) {
   	Person::class.constructors.map {
		print(it)
   	}

	//也可以通過程式碼提示直接改成這種寫法
	Person::class.constructors.map(::print)
}

data class Person(var id: Int, var name: String) {

}
複製程式碼

###Kotlin空指標安全

我們先來看一個例子,我們先建立一個Person類:

data class Person(var id: Int, var name: String) {

}
複製程式碼

然後在Java程式碼中new這個類:

public class Test { public static void main(String[] args) { //注意第二個引數傳了null Person p = new Person(1, null); } }

執行的時候發現報錯:

Exception in thread "main" java.lang.IllegalArgumentException: Parameter specified as non-null is null: method Person.<init>, parameter name
	at Person.<init>(Test.kt)
	at Test.main(Test.java:7)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
複製程式碼

因為Kotlin的類中實質上加了@notnull註解。

同樣地,我們在Kotlin中使用這個Person,也傳個null進去:

fun main(args: Array<String>) {
    val p = Person(1, null)
}
複製程式碼

你會發現,根本就編譯不過。這就是Kotlin的型別安全的體現了,把一些空指標的問題提前到了編譯階段,而不是執行階段,這一點真的很重要。

######Tips:可以通過code -- Conver Java File to Kotlin File或者直接貼上,把Java程式碼轉換Kotlin程式碼。

如果你的Person類中的name可以傳null的話,就需要加上"?"識別符號,完整的示例如下:

fun main(args: Array<String>) {
	//不會報錯了
    val p = Person(1, null)
}

data class Person(var id: Int, var name: String?) {
    
}
複製程式碼

###Kotlin中的集合

####Kotlin中的集合

與Java中用[]代表集合不一樣,在Kotlin中用Array表示集合,例如:

fun main(args: Array<String>) {

}
複製程式碼

與Java類似,可以在泛型中指定型別應該繼承哪個型別,Java中用extends關鍵字,在Kotlin中用out關鍵字,例如:

fun main(args: Array<out Bean>) {

}
複製程式碼

####集合的基本遍歷

下面是Kotlin中集合遍歷的集中方法:

fun main(args: Array<String>) {

    for (arg in args) {
        print(arg)
    }

    args.map({ print(it) })

    args.map() {
        print(it)
    }

    args.map { print(it) }

    args.map(::print)
}
複製程式碼

######Tips:命令列引數可以在run--Edit Configuration中修改。

  • 第一種沒有什麼好說的,與Java類似。

  • 第二種開始,使用了map方法進行遍歷,map方法是Kotlin中的Arrays類提供的遍歷集合的函式,定義如下:

      //map方法是一個擴充套件方法,只有一個Lambda表示式引數,接收的是一個T型別的引數,返回R型別。T型別就是我們要迭代的String型別,而R型別沒有明確指定
      public inline fun <T, R> Array<out T>.map(transform: (T) -> R): List<R> {
          return mapTo(ArrayList<R>(size), transform)
      }
    複製程式碼

因此呢,map方法可以傳進去一個 {表示式} 作為引數。而print接收一個it引數,it是迭代的String,返回的是空型別(Kotlin中空型別是Unit),完全符合map中的Lambda表示式的要求。因此可以傳進去。

  • 第三種,既然map只有一個Lambda表示式引數,那麼可以把大括號後置,這是第三種。
  • 第四中,在第三種的基礎上,既然大括號可以省略,那麼前面的()也省略了。
  • 第五種,直接把函式的引用傳進去(通過兩個分號::)

######Kotlin中的空用Unit型別表示,無返回值的函式可以這樣寫(一般無返回值直接省略而已):

fun main(args: Array<String>) :Unit{

}
複製程式碼

####使用flatMap扁平化集合

現在有一個需求:

將apple_bus_cat dog_egg_fly good_hook_it
扁平化輸出為:apple:5 bus:3 cat:3 dog:3 egg:3 fly:3 good:4 hook:4 it:2 
複製程式碼

在Java中是這樣做的:

public static void main(String[] args) {
    for (String arg : args) {
        String[] split = arg.split("_");
        for (String s : split) {
            System.out.print(s + ":" + s.length() + " ");
        }
    }
}
複製程式碼

在Kotlin中是通過flatMap進行扁平化,然後再通過map進行遍歷輸出的:

fun main(vararg args: String) {

    args.flatMap {
        it.split("_")
    }.map {
        print("$it:${it.length} ")
    }

}
複製程式碼

程式中我們用到了flatMap對集合進行了一次扁平化,返回了一個陣列,最終丟給map。下面我們來看看flatMap的原始碼:

//實際上flatMap也是傳入一個Lambda表示式,將T型別(String)的資料轉換成可迭代的R型別資料,因此String的split符合要求
public inline fun <T, R> Array<out T>.flatMap(transform: (T) -> Iterable<R>): List<R> {
    return flatMapTo(ArrayList<R>(), transform)
}

//flatMap最終會呼叫flatMapTo方法,對集合進行扁平化,把每一個轉換出來的資料都放到一個列表裡面,因此,雖然我們有apple_bus_cat dog_egg_fly good_hook_it三組資料,但是最終被切割成apple bus cat dog egg fly good hook it這樣的一個陣列,然後再通過map進行遍歷輸出即可
public inline fun <T, R, C : MutableCollection<in R>> Array<out T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C {
    for (element in this) {
        val list = transform(element)
        destination.addAll(list)
    }
    return destination
}
複製程式碼

######Tips:Kotlin中的可變長引數是用vararg關鍵字來宣告的。 ######Tips:與JS類似,雙引號""字串的拼接中可以使用$符號。 ######Tips:由於這裡迭代中需要傳參,因此不可以省略成args.map(::print)這種形式了(這種形式預設是把it傳進print方法中了)

相關文章