Kotlin 語言極簡教程 v0.1 (東海陳光劍)Kotlin 語言極簡教程

Kotlin 語言極簡教程

v0.1 (東海陳光劍)

簡介

是什麼

  • 基於 JVM 實現的靜態語言
  • JetBrains 出品。對,就是那個創造了 Android Studio 和 IntelliJ 的公司。
  • Hello World
fun main(args: Array<String>){
    println("Hello World!")
}

極簡版:

fun main(args: Array<String>) = println("Hello World!")

特性

  • 簡約:幫你減少實現同一個功能的代碼量。
  • 易懂:讓你的代碼更容易閱讀,同時易於理解。
  • 安全:移除了你可能會犯錯誤的功能。
  • 通用:基於 JVM 和 Javascript,你可以在很多地方運行。
  • 互操作性:這就意味着 Kotlin 和 Java 可以相互調用,同時 Jetbrains 的目標是讓他們 100% 兼容。

歷史

  • Java 有哪些問題?
    • 空引用(Null references):連空引用的發明者Tony Hoare 都承認這是個 billion-dollar 錯誤。不論你費多大的功夫,你都無法避免它。因爲 Java 的類型系統就是不安全的。

Speaking at a software conference called QCon London in 2009, he apologised for inventing the null reference: I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

  • 原始類型(Raw types):我們在開發的時候總是會爲了保持兼容性而卡在範型原始類型的問題上,我們都知道要努力避免 raw type 的警告,但是它們畢竟是在語言層面上的存在,這必定會造成誤解和不安全因素。
  • 協變數組(Covariant arrays):你可以創建一個 string 類型的數組和一個 object 型的數組,然後把 string 數組分配給 object 數組。這樣的代碼可以通過編譯,但是一旦你嘗試在運行時分配一個數給那個數組的時候,他就會在運行時拋出異常。
  • Java 8 存在高階方法( higher-order functions ),但是他們是通過 SAM 類型 實現的。SAM 是一個單個抽象方法,每個函數類型都需要一個對應的接口。如果你想要創建一個並不存在的 lambda 的時候或者不存着對應的函數類型的時候,你要自己去創建函數類型作爲接口。
  • 泛型中的通配符:詭異的泛型總是難以操作,難以閱讀,書寫,以及理解。對編譯器而言,異常檢查也變得很困難。
  • Kotlin 新的特性
    • Lambda 表達式
    • 類型推導
      • val a = 1
    • 數據類 (Data classes)
    • 函數字面量和內聯函數(Function literals & inline functions)
    • 函數擴展 (Extension functions)
    • 空安全(Null safety)
      • elvis操作符
        • Java var length = if(a!= null) a.length() else -1
        • Kotlin var length = a?.length() ?: -1
      • Java
String a  = null;
System.out.println(a.length());

在 Java 裏,聲明一個 string 類型,賦一個 null 給這個變量。一旦我們要打印這個字符串的時候,會在運行時曝出空指針錯誤,因爲我們在嘗試去讀一個空值。 * kotlin 寫法 * 我們定義一個空值,但是在我們嘗試操作它之前,Kotlin 的編譯器就告訴了我們問題所在:

val a:String = null

曝出的錯誤是:我們在嘗試着給一個非空類型分配一個 null。在 Kotlin 的類型體系裏,有空類型和非空類型。類型系統識別出了 string 是一個非空類型,並且阻止編譯器讓它以空的狀態存在。想要讓一個變量爲空,我們需要在聲明後面加一個 ? 號,同時賦值爲 null。

val a: String? = null
println(a.length())

現在,我們修復了這個問題,繼續向下:就像在 Java 裏一樣,我們嘗試打印 stirng 的長度,但是我們遇到了跟 Java 一樣的問題,這個字符串有可能爲空,不過幸好的是:Kotlin 編譯器幫助我們發現了這個問題,而不像 Java 那樣,在運行時爆出這個錯誤。

編譯器在長度輸出的代碼前停止了。想要讓編譯器編譯下去,我們得在調用 length 方法的時候考慮到可能爲空的情況,要麼賦值給這個 string,要麼用一個問號在變量名後,這樣,代碼執行時在讀取變量的時候檢查它是否爲空。

val a: String? = null
println(a?.length())

如果值是空,則會返回空。如果不是空值,就返回真實的值。print 遇到 null 會輸出空。

* 智能轉換(Smart casts)
* 字符串模板(String templates)
* 主構造函數(Primary constructors)
* 類委託(Class delegation)
* 類型推斷(Type inference)
* 單例(Singletons)
* 聲明點變量(Declaration-site variance)
* 區間表達式(Range expressions)

現狀&未來發展

基本類型

分支循環

if

fun main(args: Array<String>) {
    val name = if (args.isNotEmpty()) {
        args[0]
    } else {
        "World"
    }
    println("Hello, $name!")
}

val name = if (args.isNotEmpty()) args[0] else "Word"

for

enum class Language(val greeting: String) {
    EN("Hello"), ES("Hola"), FR("Bonjour")
}

class Person(var name: String, var lang: Language = Language.EN) {
    fun greet() = println("${lang.greeting}, $name!")
}



fun main(args: Array<String>) {
    val people = listOf(
       Person("Java"),
       Person("Miguel", Language.SP),
       Person("Michelle", Language.FR)
    )

    for (person in people) {
        person.greet()
    }
}

when

when(x) {
  is Int -> print(x + 1)
  is String -> print(x.length + 1)
}

數組集合類

文件 IO

面向對象編程

class Person(var name: String)

fun main(args: Array<String>) {
  val person = Person("Kotlin")
  println("Hello, $name!")
}

數據類

  • Java
  private String firstName;
  private String lastName;
  private String email;

  public String getFirstName() { return firstName; }
  public String getLastName() { return lastName; }
  public String getEmail() { return email; }

  public void setFirstName(String firstName) { this.firstName = firstName }
  public void setLastName(String lastName) { this.lastName = lastName }
  public void setEmail(String email) { this.email = email }
}
  • Kotlin
class Customer( var firstName: String ,
 var lastName: String,
 var email: String)

單例

  • object Singleton
object Logger {
  val tag = "TAG"
  fun d(message: String) {
    Log.d(tag, message)
  }
}

函數式編程

函數類型

  • (X)->Y

Lambda 表達式

  • people.forEach { it.greet() }

高階函數

  • Java 8 函數接口
// 首先要聲明一個函數接口,接受參數類型爲 T,返回類型爲 R。
public interface Function<T, R> {
  R call(T t);
}

public static <T> List<T> filter(Collection<T> items, Function<T, Boolean> f) {
  final List<T> filtered = new ArrayList<T>();
  for (T item : items) if (f.call(item)) filtered.add(item);
  return filtered;
}

filter(numbers, new Function<Integer, Boolean>() {
  @Override
  public Boolean call(Integer value) {
    return value % 2 == 0;
  }
});
  • 在 Kotlin 中
 fun <T> filter(items: Collection<T>, f: (T) -> Boolean): List<T> {
  val filtered = arrayListOf<T>()
  for (item in items) if (f(item)) filtered.add(item)
  return filtered
}

filter(numbers, { value -> value % 2 == 0 })

你可能發現了,我們沒有定義任何的函數接口,這是因爲在 Kotlin 中,函數也是一種數據類型。看到 f:(T) -> Boolean 這個語句了嗎?這就是函數類型作爲參數的寫法,f 是函數別名,T 是函數接受參數,Boolean 是這個函數的返回值。定義完成後,我們隨後就能跟調用其他函數一樣調用 f。調用 filter 的時候,我們是用 lambda 表達式來傳入過濾函數的,即:

{value -> value % 2 = 0}

由於函數類型參數是可以通過函數聲明的簽名來推導的,所以其實還有下面的一種寫法,大括號內就是第二個參數的函數體:

filter(numbers) {
  it % 2 == 0
}

函數組合示例

package com.light.sword.coursera

val lengthFun = fun(s: String): Int = s.length //lengthFun is a fun variable
val isOddFun = fun(x: Int): Boolean = x % 2 != 0

fun compose(length: (String) -> Int, isOdd: (Int) -> Boolean): (String) -> Boolean {
    return { x -> isOdd(length(x)) }
}

fun main(args: Array<String>) {
    val words = listOf("Hello", "U", "Kotlin", "Java")
    val result = words.filter(compose(lengthFun, isOddFun)) // Use lengthFun directly
    println(result) // [Hello, U]
}

擴展函數

代碼實例

fun String.lastChar(): Char = this.get(this.length - 1)

fun main(args: Array<String>) {
    println("Kotlin".lastChar())
}

Kotlin 語言極簡教程 v0.1 (東海陳光劍).png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章