《Kotlin實戰》學習筆記之第二章:Kotlin基礎
阿新 • • 發佈:2018-12-17
一、基本要素:函式和變數
1、Hello,world
fun main(args: Array<Stirng>) {
println("Hello, world!")
}
- 關鍵字
fun
宣告函式 - 陣列就是類。Kotlin沒有宣告陣列型別的特殊語法
- 可以省略每行程式碼結尾的分號
2、函式
//:後跟的是函式或引數的型別
fun max(a: Int, b: Int): Int {
return if (a > b) a else b
}
-
語句與表示式
-
表示式有值,並能作為另一個表示式的一部分使用。語句則沒有值。
-
Java中賦值操作是表示式,Kotlin中是語句
-
Kotlin中,除了迴圈(for、do和do/while)以外的大多數控制結構都是表示式
-
-
函式體
- (1)表示式函式體
- 可以去掉花括號
- 可以去掉return語句
fun max(a: Int, b: Int): Int = if (a > b) a else b
- (2)程式碼塊體函式
- 有返回值且必須顯式表示
- (1)表示式函式體
3、變數
-
書寫方式
val answer: Int = 42
val/var
關鍵字開始- 變數名: 變數型別(可省略)
-
變數種類
- (1)
val
(來自value):不可變引用- 等價於java中的final
- 該關鍵字宣告的變數不可在初始化之後再次賦值
- val無需在宣告時定義
- 儘管val引用自身是不可變的,但是它指向的物件可能是可變的
val languages = arrayListOf("Java") languages.add("Kotlin") //val指向的物件可變
- (2)
var
(來自variable):可變引用- 對應java中的普通變數
- var關鍵字允許變數在初始化後改變自己的值,但是它的型別是不能再改變的,除非手動的進行型別轉換
- 因為編譯器只會根據初始化器來推斷變數的型別
var answer = 42 answer = "no answer" //錯誤!初始化後不可改變型別
- (1)
-
“應該儘可能的使用val關鍵字來宣告所有的kotlin變數”
- 更接近函數語言程式設計的風格
4、字串模版
- 用於引用區域性變數,使用
$
或${}
- (1)直接引用字串
val name = "wang" println("Hello, $name !") 等價於 System.out.println("Hello, wang !")
- (2)使用
${}
語法插入陣列元素println("Hello,${args[0]}")
- (3)使用
${表示式}
println("Hello, ${if (args.size > 0) args[0] else "someone"}!")
- (1)直接引用字串
二、類和屬性
1、值物件
class Person(val name: String)
- 這種只有資料沒有其他程式碼的類被稱作
值物件
- 等價於javabean
- 在Kotlin中,public是預設可見性,可省略
- 因此可以直接呼叫相關屬性,但其根本也是呼叫了getter
//Kotlin中建立物件不需要new val person = Person("Bob", true) //在其他類中可以直接呼叫屬性 println(person.name)
2、屬性
class Person (
val name: String //只讀屬性
var isMarried: Boolean //可寫屬性
)
-
Kotlin中這種簡潔的資料類宣告隱藏了和原始Java程式碼相同的底層實現:它是一個欄位都私有的類
-
關鍵字:
- (1)
val
關鍵字宣告的變數為只讀屬性:- 生成一個欄位
- 生成一個簡單的getter
- (2)
var
關鍵字宣告的是可寫屬性:- 生成一個欄位
- 生成一個getter
- 生成一個setter
- (1)
3、自定義訪問器
class Rectangle(val height: Int, val width: Int) {
val isSquare: Boolean
//自定義isSquare屬性的getter
//法1:
get() {
return height == width
}
或
//法2:
get() = height == width
}
4、Kotlin原始碼佈局:目錄和包
-
Kotlin不區分匯入的是類還是函式
- 可以只匯入某個類的某個函式
- 可以在包名稱後加上.*來匯入特定包中定義的所有宣告
-
Kotlin中,可以把多個類放在同一個檔案中
三、表示處理和選擇:列舉和“when”
1、宣告列舉類
- Kotlin中,
enum
是一個軟關鍵字,即只有在class
前使用才會有特殊含義,其他地方可以當作普通名稱使用
enum class ColorEnum(var r: Int, val g: Int, val b: Int) {
//初始化列舉物件(注意保持引數一致)
RED(255, 0, 0), ..., ..., ...;
//定義其他方法
}
- 初始化列舉物件時是kotlin中唯一需要使用分號的地方
- 使用分號將列舉常量列表和方法定義分開
2、使用when
關鍵字處理列舉累(相當於switch
)
when
是一個又返回值的表示式,可以寫一個直接返回when
表示式的表示式體函式
fun getMnemonic(color: Color) =
when (color) {
Color.RED -> "紅色"
Color.ORANGE -> "橙色"
...
}
- 可以將多個條件值合併到同一個分支
- 條件值之間通過逗號隔開
- 等同於
||
fun getWarmth(color: Color) = when(color) {
Color.RED, Color.ORANGE, Color.YELLEW -> "紅色或橙色或黃色"
Color.GREEN -> "綠色"
···
}
- 匯入列舉常量省略列舉類名
improt ch2.colors.Color
import ch2.colors.Color.*
fun getWarmth(color: Color) = when(color) {
Color.RED, Color.ORANGE, Color.YELLEW -> "紅色或橙色或黃色"
Color.GREEN -> "綠色"
···
}
3、在when
中使用任意物件
- kotlin中,
when
結構允許使用任意型別的物件
4、使用不帶引數的when
- 如果沒有給
when
表示式提供引數,粉質條件就是任意的布林表示式
when {
(a == b) || (b == c) -> "a等於b或b等於c"
...
}
5、智慧轉換:合併型別檢查和轉換(相當於“多型”)
-
(1)宣告類的繼承及實現關係
- 宣告類的時候,使用一個
冒號(:)
後面跟上介面名稱,來標記這個類實現了這個介面 - 通過被繼承或實現的類定義時是
class
還是interface
來定義:
表示的是繼承還是實現 - kotlin同樣是“單繼承,多實現”
- 宣告類的時候,使用一個
-
(2)通過
is
檢查變數型別(相當於Java中的instanceOf
)- 智慧轉換:當一個物件通過
is
檢查過型別後,即可直接呼叫該物件的相關成員- 在Java中,
instanceOf
檢查完後還需要一次型別轉換才能直接呼叫物件的成員,而Kotlin通過智慧轉換省略了這一步
- 在Java中,
- 智慧轉換:當一個物件通過
if (e is Sum) {
return println("$e.right, ${e.left)
}
- (3)通過
as
進行顯式的型別轉換- eg:
val n = e as Num
(將e轉為Num型別)
- eg:
6、重構:用“when”代替“if”
-
(1)
if
表達- 如果if分支中只有一個表示式,花括號可以省略
- 如果if分支是一個程式碼塊,則程式碼塊中的最後一個表示式會被作為結果返回
-
(2)
when
中的else
(等同於Java中switch的default)
fun eval(e: Expr): Int =
when (e) {
is Num -> //is xx 用於檢查
e.value //
is Sum ->
eval(e.right) + eval(e.left)
else ->
throw IllegalArgumentException("Unknown expression")
}
7、程式碼塊作為“if”和“when”分支
- 對於
if、when、try/catch
結構來說,如果是程式碼塊體表示,最後一個表示式就是結果(返回值)
四、迭代事物:“while”迴圈和“for”迴圈
1、for
迴圈
- kotlin中,
for
僅以唯一一種形式存在:for <item> in <elements>
(類似於for each
)
for(i in 1..100) { //其中i在使用時宣告
...
}
2、while
迴圈
- (1)
while
型- 當condition為true時執行迴圈體
while (condition) {
...
}
- (2)
do..while
型- 迴圈體第一次會無條件的執行
- 從第二次開始只有當condition為true時才執行
do {
...
} whlie (condition)
3、迭代數字:區間和數列
-
(1)區間
- 定義:區間本質上就是兩個值之間的間隔,這兩個值通常是數字。一個起始值,一個結束值。
- 關鍵字:使用
..
運算子表示區間 - 示例:
val onToTen = 1..10
- 注意:Kotlin的區間是包含或閉合的,意味著始終包含結束值
-
(2)數列
- 定義:整數區間,且能迭代區間中的所有值,這樣的區間被稱作數列
-
(3)帶步長的數列
- 關鍵字:
downTo
、step
- 特性:允許跳過一些數字。步長可以是負數。
- 示例:
for(i in 100 downTo 1 step 2) { //從100開始遞減,由遞減1變為遞減2, }
- 關鍵字:
-
(3)半閉合區間
- 定義:不包含結束值的區間
- 關鍵函式:
until
- 示例:
for(x in 0 until size)
等價於for(x in 0..size - 1)
4、迭代map
-
區間允許迭代:
- 數字
- 字元
- 展開迭代集合中的元素
-
展開迭代map
- 可以使用
map[key]讀取值,並使用map[key] = value
設定他們
- 可以使用
val binaryReps = TreeMap<char, String>()
//插入資料
for(c in "A".."F") {
val binary = Integer.toBinaryString(c.toInt())
binaryReps[c] = binary //根據鍵c將值儲存到map中
}
for ((letter, binary) in binaryReps) {
//將
println("$letter = $binary")
}
- 展開迭代List
list.withIndex()
val list = arrayListOf("10", "11", "1001")
for ((index, element) in list.withIndex()) {
println("$index: $element")
}
5、使用“in”檢查集合和區間的成員
-
使用
in
運算子或它的逆運算子!in
來檢查這個值是否在區間中 -
區間不僅限於字元和數字
- 假如有一個支援例項比較操作的任意類(實現了
java.lang.Comparable
介面),就能建立這種型別的物件區間
- 假如有一個支援例項比較操作的任意類(實現了
-
in
檢查同樣適用於集合println("Kotlin" in setOf("Java", "Scala")) 輸出:false
五、Kotlin中的異常
- Kotlin中throw結構是一個表示式,能作為另一個表示式的一部分使用
1、“try”、“catch”和“finally”
-
Kotlin並不區分受檢異常和未受檢異常
- 不用制定函式丟擲的異常
- 不強制處理異常
-
所以throw子句不一定會出現在程式碼中
2、 “try”作為表示式
- try可引入一個表示式,將它的值賦給一個變數
- 總是需要用花括號將語句主題括起來
fun readNumber(reader: BufferedReader) { val number = try { //將“try”作為表示式賦值給number Integer.parseInt(reader.readLine()) } catch (e: NumberFormatException) { return } println(number) }