Kotlin教程(一)基礎

寫在開頭:本人打算開始寫一個Kotlin系列的教程,一是使本身記憶和理解的更加深入,二是能夠分享給一樣想學習Kotlin的同窗。系列文章的知識點會以《Kotlin實戰》這本書中順序編寫,在將書中知識點展現出來同時,我也會添加對應的Java代碼用於對比學習和更好的理解。java

Kotlin教程(一)基礎
Kotlin教程(二)函數
Kotlin教程(三)類、對象和接口
Kotlin教程(四)可空性
Kotlin教程(五)類型
Kotlin教程(六)Lambda編程
Kotlin教程(七)運算符重載及其餘約定
Kotlin教程(八)高階函數
Kotlin教程(九)泛型git


Kotlin與Java互轉

Kotlin代碼在編譯後都會轉成Java文件,對於編寫的Kotlin,咱們能夠經過工具提早看到轉換後的Java代碼,具體方式是: 在as中找到Tools>Kotlin>Show Kotlin Bytecode,而後點面板上的Decompile。express

對於以前寫好的Java代碼,咱們也能夠用工具轉換成Kotlin代碼,方法是: Code > Convert Java File To Kotlin File編程

函數和變量

Hello, world!

學習就從如何用Kotlin編寫一個「Hollo World」開始吧!先看熟悉的Java:小程序

public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
複製代碼

而後那,是Kotlin的寫法:數組

fun main(args: Array<String>) {
    println("Hello, world!")
}
複製代碼

能夠看到Kotlin中:bash

fun 關鍵字用來聲明一個函數;dom

main 是方法名;函數

args: Array<String>表示參數,能夠發現於java中先類型後變量名相反,Kotlin中是先變量名,而後:,而後是類型聲明。工具

Kotlin中沒有聲明數組的特殊語法,而是用Array表示數組,有點相似集合的感受;

println代替了System.out.println,這是Kotlin標準庫給Java標準庫函數提供了許多語法更簡潔的包裝;

不知道你有沒有注意到;,Kotlin中省略了分號。

函數

熟悉Java的你可能會想返回值在哪裏那?怎麼沒有那?

fun max(a: Int, b: Int): Int {
    return if (a > b) a else b
}
複製代碼

: Int這裏就出現,表示返回值是一個int類型,那爲何上面那個函數沒有寫那?其實上面那個函數也有返回值,返回值是空,也就是void,在Kotlin中實際上是: Unit,而: Unit默承認以省略,因此就看不到返回值的聲明瞭。

一樣方法在對比Java的看下:

public static int max(int a, int b) {
        if (a > b) {
            return a;
        } else {
            return b;
        } 
    }
複製代碼

是否是發現了方法體中if的使用好像有區別? 在Kotlin中,if是表達式,而不是語句。語句和表達式的區別在於,表達式有值,而且能做爲另外一個表達式的一部分使用;而語句老是包圍着它的代碼塊中的頂層元素,而且沒有本身的值。在Java中,所用的控制結構都是語句。而在Kotlin中,除了循環(for,do,do/while)之外大多數控制結構都是表達式。

表達式函數體

若是一個方法的函數體是由單個表達式構成的,能夠用這個表達式做爲完整的函數體,而且去掉花括號和return語句:

fun max(a: Int, b: Int) = if (a > b) a else b
複製代碼

ps:在as中經過alt+enter能夠喚起操做,提供了在兩種函數風格之間轉換的方法:"Convert to expression body"(轉換成表達式函數體)和 "Convert to block body"(轉換成代碼塊函數體)

細心的你或許注意到此處的表達式函數體也沒有寫出返回類型,做爲一門靜態類型的語言,Kotlin不是要求每一個表達式都應該在編譯期具備類型嗎?事實上,每一個變量和表達式都有類型,每一個函數都有返回類型。可是對錶達式體函數來講,編譯器會分析做爲函數體的表達式,並把它的類型做爲函數的返回類型,即便沒有顯示得寫出來。這種縫隙一般被稱做類型推導

變量

在Java中變量的聲明是從類型開始的,就像這樣:

final String str = "this is final string";
int a = 12;
複製代碼

可是在Kotlin中這樣是行不通的,由於許多變量聲明的類型均可以省略。因此在Kotlin中以關鍵字開始,而後是變量名稱,最後能夠加上類型(也能夠省略):

val str: String = "this is a final string"
var a = 12
複製代碼

其中: String也是能夠省略的,經過=右邊推導出左邊變量的類型是String,就像a變量省略類型。

可變變量和不可變變量

聲明變量的關鍵字有兩個: val(來自value)——不可變引用。在初始化以後不能再次賦值,對應Java中final修飾符。 var(來自variable)——可變引用。這種變量的值能夠被改變,對應Java中的普通變量。

雖然var表示可變,而且如上面看到的也省略的類型,乍一看彷佛和js等腳本語言相似,能夠直接賦值另外一種類型的值,好比這樣:

var a = 12
a = "string"//錯誤
複製代碼

但實際上,這樣作是錯誤的,即便var關鍵字容許變量改變本身的值,但它的類型倒是改變不了的。此處a變量在首次賦值時就肯定了類型,這裏的類型是Int,再次賦值String類型的值時就會提示錯誤,而且運行也會發生ClassCastException。

注意,儘管val引用自身是不可變的,可是它指向的對象多是可變的,例如:

val languages = arrayListOf("Java")
languages.add("Kotlin")
複製代碼

其實和Java中一致,final定義一個集合,集合中的數據是能夠改變的。

###字符串模板

val name = "HuXiBing"
println("Hello, $name!")
複製代碼

這是一個Kotlin的新特性,在代碼中,你申明瞭一個變量name,而且後面的字符串字面值中使用了它。和許多腳本語言同樣,Kotlin讓你能夠在字符串字面值中引用局部變量,只須要在變量名稱前面加上字符$,這等價於Java中的字符串連接 "Hello, " + name + "!" ,效率同樣可是更緊湊。 經過轉換成Java代碼,咱們能夠看到這兩句代碼實際上是這樣的:

String name = "HuXiBing";
String var3 = "Hello, " + name + '!';
System.out.println(var3);
複製代碼

固然,表達式會進行靜態檢查,若是你試着引用一個不存在的變量,代碼根本不會編譯。 若是要在字符串中使用$,你須要對它轉義:println("\$x")會打印$x,並不會吧x解釋成變量的引用。 還能夠引用更復雜的表達式,而不是僅限於簡單的變量名稱,只須要把表達式用花括號括起來:

println("1 + 2 = ${1 + 2}")
複製代碼

還能夠在雙引號中直接嵌套雙引號,只要它們在某個表達式的範圍內(即花括號內):

val a = 12
println("a ${if (a >= 10) "大於等於10" else "小於10"}")
複製代碼

類和屬性

先來看一個簡單的JavaBean類Person,目前它只有一個屬性:name。

public class Person {
    private final String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
複製代碼

在Java中,構造方法的方法體經常包含徹底重複的代碼:它把參數賦值給有着相同名稱的字段。在Kotlin中,這種邏輯不用這麼多的樣板代碼就能夠表達。 使用Convert Java File To Kotlin File將這個對象轉換成Kotlin:

class Person(val name: String)
複製代碼

這種只有數據沒有其餘代碼的類一般被叫作值對象,許多語言都提供簡明的語法來聲明它們。 注意從Java到Kotlin的轉換過程當中public修飾符消失了,在Kotlin中默認是public,因此能夠省略它。

屬性

類的概念就是把數據和處理數據的代碼封裝成一個單一的實體。在Java中,數據存儲在字段中,一般仍是私有的。若是想讓類的使用者訪問到數據,得提供訪問器方法:一個getter,可能還有一個setter。在Person類中你已經看到了訪問器的例子。setter還能夠包含額外的邏輯,包括汗蒸傳給它的值、發送關於變化的通知等。 在Java中,字段和其訪問器的組合經常被叫作屬性,在Kotlin中,屬性時頭等的語言特性,徹底代替了字段和訪問器的方法。在類中聲明一個屬性和聲明一個變量同樣:使用val和var關鍵字。聲明成val的屬性是隻讀的,而var屬性是可變的。

class Person(
        val name: String,//只讀屬性,生成一個字段和一個簡單的getter
        var isMarried: Boolean//可寫屬性:生成一個字段、一個getter、一個setter
)
複製代碼

看看轉換成Java的代碼可能更清晰一點:

public final class Person {
   @NotNull
   private final String name;
   private boolean isMarried;

   @NotNull
   public final String getName() {
      return this.name;
   }

   public final boolean isMarried() {
      return this.isMarried;
   }

   public final void setMarried(boolean var1) {
      this.isMarried = var1;
   }

   public Person(@NotNull String name, boolean isMarried) {
      super();
      Intrinsics.checkParameterIsNotNull(name, "name");
      this.name = name;
      this.isMarried = isMarried;
   }
}
複製代碼

簡單的說就是平時咱們用代碼模板生成的bean,在Kotlin中連模板都不須要使用了,編譯時會自動生成對應的代碼。 在Java中使用應該比較熟悉了,是這個是這樣的:

Person person = new Person("HuXiBing", true);
System.out.println(person.getName());
System.out.println(person.isMarried());
複製代碼

生成的getter和setter方法都是在屬性名稱前加上get和set前綴做爲方法名,可是有一種例外,若是屬性時以is開頭,getter不會增長前綴,而它的setter名稱中is會被替換成set。因此你調用的將是isMarried()。 而在Kotlin中使用是這樣的:

val person = Person("HuXiBing", true)     //調用構造方法不須要關鍵字new
println(person.name)    //能夠直接訪問屬性,但調用的時getter
println(person.isMarried)
複製代碼

在Kotlin中能夠直接引用屬性,不在須要調用getter。邏輯沒有變化,但代碼更簡潔了。可變屬性的setter也是這樣:在Java中,使用person.setMarried(false)來表示離婚,而在Kotlin中,能夠這樣寫:person.isMarried = false

自定義訪問器

若是getter和setter方法中須要額外的邏輯,能夠經過自定義訪問器的方式實現。例如如今有這樣一個需求:聲明一個矩形,它能判斷本身是不是一個正方形。不須要一個單獨的字段來存儲這個信息,由於能夠隨時經過檢查矩形的長寬是否相等來判斷:

class Rectangle(val height: Int, val width: Int) {
    val isSquare: Boolean
        get() {//聲明屬性的getter
            return height == width
        }
}
複製代碼

屬性isSquare不須要字段來保存它的值,它只有一個自定義實現的getter,它的值是每次訪問屬性的時候計算出來的。還記得以前的表達式函數體嗎?此處也能夠轉成表達式體函數:get() = height == width。 一樣的看下轉換成Java代碼更好理解:

public final class Rectangle {
   private final int height;
   private final int width;

   public final boolean isSquare() {
      return this.height == this.width;
   }

   public final int getHeight() {
      return this.height;
   }

   public final int getWidth() {
      return this.width;
   }

   public Rectangle(int height, int width) {
      this.height = height;
      this.width = width;
   }
}
複製代碼

Kotlin源碼佈局:目錄和包

與Java相似,每個Kotlin文件都能以一條package語句開頭,而文件中定義的全部聲明(類、函數及屬性)都會被放到這個包中。若是其餘文件中定義的聲明也有相同的包,這個文件能夠直接使用它們;若是包不相同,則須要導入它們。和Java同樣,導入語句放在問價你的最前面使用關鍵字import

package com.huburt.imagepicker

import java.util.Random
複製代碼

Java中的包和導入聲明:

package com.huburt.imagepicker;

import java.util.Random;
複製代碼

僅僅省略了; 還有點不一樣的時Kotlin不區分導入是類仍是函數(是的Kotlin的函數能夠單獨存在,不是必定要聲明在類中)。例如:

import com.huburt.other.createRandom
複製代碼

com.huburt.other是包名,createRandom是方法名,直接定義在Kotlin文件的頂層函數。 在Java中,要把類放在和包結構相匹配的文件與目錄結構中。而在Kotlin中包層級機構不須要遵循目錄層級結構,可是無論怎樣,遵循Java的目錄佈局更根據包結構把源碼文件放到對應的目錄中是個更好的選擇,避免一些不期而遇的錯誤。

表示和處理選擇:枚舉和When

聲明枚舉

Kotlin中聲明枚舉:

enum class Color {
    RED, ORANGE, YELLOW, GREEN, BLUE
}
複製代碼

而Java中枚舉的聲明:

enum Color {
    RED, ORANGE, YELLOW, GREEN, BLUE
}
複製代碼

這是極少數Kotlin聲明比Java使用了更多關鍵字的例子(多了class關鍵字)。Kotlin中,enum是一個軟關鍵字,只有當它出如今class前面是纔有特殊的意義,在其餘地方能夠把它當作普通的名稱使用,與此不一樣的是,class任然是一個關鍵字,要繼續使用名稱clazz和aClass來聲明變量。 和Java同樣,枚舉並非值得列表,能夠給枚舉類聲明屬性和方法:

enum class Color(val r: Int, val g: Int, val b: Int) {

    RED(255, 0, 0), ORANGE(255, 165, 0),
    YELLOW(255, 255, 0), GREEN(0, 255, 255),
    BLUE(0, 0, 255);

    fun rgb() = (r * 256 + g) * 256 + b
}
複製代碼

枚舉常量用的聲明構造的方法和屬性的語法與以前你看到的常規類同樣。當你聲明每一個枚舉常量的時候,必須提供該常量的屬性值。注意這個向你展現了Kotlin語法中惟一必須使用分號(;)的地方:若是要在枚舉類中定義任何方法,就要使用分號把枚舉常量列表和方法定義分開。

使用When處理枚舉類

對於Java,一般使用switch來匹配枚舉,例如這樣:

public String getColorStr(Color color) {
        String str = null;
        switch (color) {
            case RED:
                str = "red";
                break;
            case BLUE:
                str = "blue";
                break;
            case GREEN:
                str = "green";
                break;
            case ORANGE:
                str = "orange";
                break;
            case YELLOW:
                str = "yellow";
                break;
        }
        return str;
    }
複製代碼

而Kotlin中沒有switch,取而代之的是when。和if類似,when是一個有返回值的表達式,所以咱們寫一個直接返回when表達式的表達式體函數:

fun getColorStr(color: Color) =
        when (color) {
            Color.RED -> "red"
            Color.ORANGE -> "orange"
            Color.YELLOW -> "yellow"
            Color.GREEN -> "green"
            Color.BLUE -> "blue"
        }
//調用方法
println(getColorStr(Color.RED))
複製代碼

上面的代碼根據傳進來的color值找到對應的分支。和Java不同,你不須要在每一個分支都寫上break語句(在Java中遺漏break一般會致使bug)。若是匹配成功,只有對應的分支會執行,也能夠把多個值合併到同一個分支,只須要逗號(,)隔開這些值。

fun getColorStr(color: Color) =
        when (color) {
            Color.RED, Color.ORANGE, Color.YELLOW -> "yellow"
            Color.GREEN -> "neutral"
            Color.BLUE -> "cold"
        }
複製代碼

若是以爲寫了太多的Color,能夠經過導入的方式省略:

import com.huburt.other.Color //導入類
import com.huburt.other.Color.* //導入枚舉常量

fun getColorStr(color: Color) =
        when (color) {
            RED, ORANGE, YELLOW -> "yellow" //直接使用常量名稱
            GREEN -> "neutral"
            BLUE -> "cold"
        }
複製代碼

在When結構中使用任意對象

Kotlin中的when結構比Java中switch強大的多。switch要求必須使用常量(枚舉常量、字符串或者數字字面值)做爲分支條件。而when容許使用任何對象。咱們使用這種特性來寫一個函數來混合兩種顏色:

fun mix(c1: Color, c2: Color) {
    when (setOf(c1, c2)) {
        setOf(Color.RED, Color.YELLOW) -> Color.ORANGE
        setOf(Color.YELLOW, Color.BLUE) -> Color.GREEN
        else -> throw Exception("Dirty color")
    }
}
複製代碼

setOf是Kotlin標準函數庫中一個方法,用於建立Set集合(無序的)。 when表達式把setOf(c1, c2)生成的set集合依次和全部的分支匹配,直到某個分支知足條件,執行對應的代碼(返回混合後顏色值或者拋出異常)。 能使用任何表達式做爲when的分支條件,不少狀況下會讓你的代碼既簡潔又漂亮。

使用不帶參數的When

你可能意識到上面的例子效率多少有些低。沒此調用這個函數的時候它都會建立一些Set實例,僅僅是用來檢查兩種給定的顏色是否和另外兩種顏色匹配。通常這不是什麼大問題,可是若是這個函數調用很頻繁,它就很是值得用另外一種方式重寫。來避免建立額外的垃圾對象。

fun mixOptimized(c1: Color, c2: Color) =
        when {
            (c1 == Color.RED && c2 == Color.YELLOW) ||
                    (c1 == Color.YELLOW && c2 == Color.RED) -> Color.ORANGE

            (c1 == Color.BLUE && c2 == Color.YELLOW) ||
                    (c1 == Color.YELLOW && c2 == Color.BLUE) -> Color.GREEN
            
            else -> throw Exception("Dirty color")
        }
複製代碼

若是沒有給when表達式提供參數,分支條件就是任意的布爾表達式mixOptimized方法和上面那個例子作了如出一轍的事情,這種寫法不會穿件額外的對象。

智能轉換

在Java中常常會有這樣一種情形:用父類申明引用一個子類對象,當要使用子類的某個方式時,須要先判斷是不是哪一個子類,若是是的話在強轉成子類對象,調用子類的方法,用代碼的話就是以下的狀況:

class Animal {

}

class Dog extends Animal {
    public void dig() {
        System.out.println("dog digging");
    }
}

Animal a = new Dog();
if (a instanceof Dog) {
     ((Dog) a).dig();
}
複製代碼

在Kotlin中,編譯器會幫你完成強轉的工做。若是你檢查過一個變量是某種類型,後面就不須要轉換它,就能夠把它當作你檢查過的類型使用(調用方法等),這就是智能轉換。

val d = Animal()
if (d is Dog) {
    d.dig()
}
複製代碼

這裏is是檢查一個變量是不是某種類型(某個類的實例),至關於Java中的instanceof。能夠看到d變量是一個Animal對象,經過is判斷是Dog後,無需強轉就能調用Dog的方法。 智能轉換隻在變量通過is檢查且且以後再也不發生變化的狀況下有效。當你對一個類的屬性進行智能轉換的時候,這個屬性必須是一個val屬性,並且不能有自定義的訪問器。不然,每次對屬性的訪問是否都能返回相同的值將無從驗證。

在Kotlin中用as關鍵字來顯示轉換類型(強轉):

val d = Animal()
val dog = d as Dog
複製代碼

ps:其實只是省略強轉代碼,我的感受做用不是很明顯。

用When代替If

Kotlin和Java中if有什麼不一樣,以前已經提到過了。如if表達式用在適用Java三元運算符的上下文中:if (a > b) a else b (Kotlin)和a > b ? a : b(Java)效果同樣。Kotlin沒有三元運算符,由於if表達式有返回值,這一點和Java不一樣。 對於較少的判斷分支用if沒有問題,可是較多的判斷分支則用when是更好的選擇,有相同的做用,而且都是表達式,都有返回值。

代碼塊做爲If和When的分支

上面的例子知足條件的分支執行只有一行代碼,但若是某個分支中代碼不止一行還如何處理那?固然是把省略的{}加上做爲代碼塊啦:

val a = 1
val b = 2
var max = if (a > b) {
   println(a)
   a
} else b

var max2 = when {
   a > b -> {
     println(a)
     a
  }
  else -> b
}
複製代碼

代碼塊中最後一個表達式就是結果,也就是返回值。 對比Java的代碼:

int a = 1;
int b = 2;
int max;
if (a > b) {
   System.out.println(a);
   max = a;
} else {
    max = b;
}
//沒法使用switch
複製代碼

少了賦值操做,而且when的使用在多條件的狀況下也更方便。是否是慢慢發現Kotlin的美妙了?

循環

While循環

Kotlin中whiledo-while循環與Java徹底一致,這裏再也不過多敘述。

迭代數字:區間和數列

Kotlin中有區間的概念,區間本質上就是兩個值之間的間隔,這兩個值一般是數字:一個起始值,一個結束值,使用..運算符來表示區間:

val oneToOne = 1 .. 10
複製代碼

注意Kotlin的區間是包含的或者閉合的,意味着第二個值始終是區間的一部分。若是不想包含最後那個數,可使用函數until建立這個區間:val x = 1 until 10 ,等同於val x = 1 .. 9

你能用整數區間作的最基本的事情就是循環迭代其中全部的值。若是你能迭代區間中全部的值,這樣的區間被稱做數列。 咱們用整數迭代來玩Fizz-Buzz遊戲。遊戲玩家輪流遞增計數,遇到能被3整除的數字就用單詞fizz代替,遇到能被5整除的數字則用單詞buzz代替,若是一個數字是3和5的公倍數,你得說FizzBuzz。

fun fizzBuzz(i: Int) = when {
    i % 15 == 0 -> "FizzBuzz"
    i % 5 == 0 -> "Buzz"
    i % 3 == 0 -> "Fizz"
    else -> "$i"
}

fun play() {
    for (i in 1..100) {
        print(fizzBuzz(i))
    }
}
複製代碼

Kotlin中for循環僅以惟一一種形式存在,其寫法:for <item> in <elements>。 區間1 .. 100 也就是<elements>,所以上面這個例子遍歷了這個數列,並調用fizzBuzz方法。 假設想把遊戲變得複雜一點,那咱們能夠從100開始倒着計數,而且只計偶數。

for (i in 100 downTo 1 step 2) {
     print(fizzBuzz(i))
}
複製代碼

這裏100 downTo 1是遞減的數列(默認步長是1),而且設置步長step爲2,表示每次減小2。

迭代map

咱們用一個打印字符二進制表示的小程序做爲例子。

val binaryReps = TreeMap<Char, String>()//使用TreeMap讓鍵排序
    for (c in 'A'..'F') {//使用字符區間迭代從A到F之間的字符
        val binary = Integer.toBinaryString(c.toInt())//吧ASCII碼換成二進制
        binaryReps[c] = binary//根據鍵c把值存入map
    }
    for ((letter, binary) in binaryReps) {//迭代map,把鍵和值賦給兩個變量
        println("$letter = $binary")
    }
複製代碼

.. 語法不只能夠建立數字區間,還能夠建立字符區間。這裏使用它迭代從A到F的全部字符,包括F。 for循環容許展開迭代中集合的元素(map的鍵值對),把展開的結果存儲到兩個獨立的變量中:letter是鍵,binary是值。 map中能夠根據鍵老訪問和更新map的簡明語法。使用map[key]讀取值,並使用map[key] = value設置它們,而不須要地愛用get和put。這段binaryReps[c] = binary等價於Java中的binaryReps.put(c, binary);

你還可使用展開語法在迭代集合的同時跟蹤當前項的下標。不須要建立一個單獨的變量來存儲下標並手動增長它:

val list = arrayListOf("10", "11", "1001")
    for ((index, element) in list.withIndex()) {
        println("$index : $element")
    }
複製代碼

使用in檢查集合和區間的成員

使用in運算符來檢查一個值是否在區間中,或者它的逆運算!in來檢查這個值是否不在區間中。下面展現瞭如何使用in來檢查一個字符是否屬於一個字符區間。

fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'z'
fun isNotDigit(c: Char) = c !in '0'..'9'
複製代碼

這種檢查字符是不是英文字符的技巧看起來很簡單。在底層,沒有什麼特別處理,依然會檢查字符的編碼是否位於第一個字母編碼和最後一個字母編碼之間的某個位置(a <= c && c <= z)。可是這個邏輯被簡潔地隱藏到了標準庫中的區間類實現。 in運算符合!in也適用於when表達式。

fun recognize(c: Char) = when (c) {
    in '0'..'9' -> "It's a digit!"
    in 'a'..'z', in 'A'..'z' -> "It's a letter!"
    else -> "I don't know..."
}
複製代碼

Kotlin中的異常

Kotlin的異常處理語句基本形式與Java相似,除了不須要new關鍵字,而且throw結構是一個表達式,能做爲另外一個表達式的一部分使用。

val  b = if (a > 0) a else throw Exception("description")
複製代碼

try、catch、finally

和Java同樣,使用帶有catchfinally子句的try結構來處理異常,下面這個例子從給定的文件中讀取一行,嘗試把它解析成一個數字,返回這個數字;或者當這一行不是一個有效數字時返回null

fun readNumber(reader: BufferedReader): Int? {
    try {
        val line = reader.readLine()
        return Integer.parseInt(line)
    } catch (e: NumberFormatException) {
        return null
    } finally {
        reader.close()
    }
}
複製代碼

Int? 表示值多是int類型,也可能null,Kotlin獨特的null機制,不帶?標識的聲明沒法賦值null,在以後的文章中會具體介紹。

和Java最大的區別就是throws子句沒有出如今代碼中:若是用Java來寫這個函數,你會顯示地在函數聲明的後寫上throws IOException。你須要這樣作的緣由是IOException是一個受檢異常。在Java中,這種異常必須顯示地處理。必須申明你的函數能拋出的全部受檢異常。若是調用另一個函數,須要處理這個函數的受檢異常,或者聲明你的函數也能拋出這些異常。 和其餘許多如今JVM語言同樣,Kotlin並不區分受檢異常和未受檢異常。不用指定函數拋出的異常,並且能夠處理也能夠不處理異常。這種設計是基於Java中使用異常實踐作出的決定。經驗顯示這些Java規則經常致使許多毫無心義的從新拋出或者忽略異常的代碼,並且這些規則不能老是保護你免受可能發生的錯誤。

try做爲表達式

Kotlin中try關鍵字就像if和when同樣,引入了一個表達式,能夠把它的值賦給一個變量。例如上面這個例子也能夠這樣寫:

fun readNumber(reader: BufferedReader): Int? =
        try {
            val line = reader.readLine()
            Integer.parseInt(line)
        } catch (e: NumberFormatException) {
            null
        } finally {
            reader.close()
        }
複製代碼

若是一個try代碼塊執行一切正常,代碼塊中最後一個表達式就是結果。若是捕獲到了一個異常,相應的catch代碼塊中最後一個表達式就是結果。

相關文章
相關標籤/搜索