在19年的Google I/O大會上,Kotlin 成爲 Android 開發首選語言。而著名的OkHttp 已經開始用 Kotlin 進行重寫工做。是時候經過寫博客概括來鞏固Kotlin基礎知識。java
Kotlin中使用val關鍵字聲明常量(即變量初始化以後不可再次賦值),var關鍵字聲明變量。android
變量定義時能夠不顯示指定類型,編譯器會根據其初始化器的類型進行推斷。數組
//自動推斷出 `Int` 類型
var daqi = 1
//能夠顯式地指定變量的類型
val a :String = "daqi"
//若是變量沒有初始化器,須要顯式地指定它的類型
val c: Int
c = 3
複製代碼
當編譯器能確保val變量只有惟一一條初始化語句會被執行,能夠根據條件對它初始化不一樣的值。安全
val daqi:String
var isChange = true
if (isChange){
daqi = "1"
}else{
daqi = "2"
}
複製代碼
val變量的引用自身是不可變的,可是它指向的對象是可變的。bash
val languages = arrayListOf("Java")
languages.add("Kotlin")
複製代碼
var 關鍵字容許變量改變本身的值,但不能改變本身的類型。ide
var daqi = 1
//編譯不經過
daqi = ""
複製代碼
(三)、定義函數 Kotlin 中使用 fun 關鍵字聲明函數。 完整的函數定義:函數
修飾符(默認public)+ fun + 方法名 + (參數列表) :返回值 {
函數體
}
複製代碼
public fun daqi(name:String):String {
}
複製代碼
當單個表達式構成完整的函數體時,能夠直接去掉 {} 和 return 語句,函數的返回值類型編譯器也會自動推斷。這種函數就是表達式函數。工具
fun sum(a: Int, b: Int) = a + b
複製代碼
語句和表達式的區別在於:post
在 Java 中,全部的控制結構都是語句。而在 Kotlin 中,除了循環( for, do 和 do/while )之外大多數控制結構都是表達式(例如:if、 when 以及 try 屬於表達式)ui
表達式函數不光用在些簡單的單行函數中 ,也能夠用在對更復雜的單個表達式求值的函數中。
fun max(a: Int, b: Int ) = if (a > b) a else b
複製代碼
相似Java的返回值類型爲void的函數
fun daqi():Unit{
}
複製代碼
可省略Unit類型
fun daqi(){
}
複製代碼
在 Java 中,當須要打印變量描述和其值時,每每以下打印:
String str = "daqi";
System.out.println("str = " + str);
複製代碼
Kotlin支持字符串模板,能夠在字符串中引用局部變量,但須要在變量名前加上$。表達式會進行靜態檢查, 若是$引用一個不存在的變量,代碼不會編譯經過。
val str = "daqi"
printlin("str = $str")
複製代碼
$不只限於引用於簡單的變量名稱,還能夠引用更復雜的表達式。
val daqi = intArrayOf(1,2,3)
println("${daqi[0]}")
複製代碼
在$引用的表達式內(即花括號{}中)能夠直接嵌套雙引號
println("daqi的第一個元素: ${if(daqi.size > 0) daqi[0] else "null"}")
複製代碼
當須要打印$符號時,能夠對其進行轉義,或者利用表達式對其進行打印:
//打印結果爲:$str
val str = "daqi"
println("\$str")
println(${'$'}daqi)
複製代碼
在java中定義一個簡單類:
public class Person{
private final String name;
public Person(String name){
this.name = name;
}
public String getName(){
return name;
}
}
複製代碼
用Kotlin寫的Person類(默認public修飾)
class Person(val name:String)
複製代碼
延伸:若想知道Kotlin對應的具體Java實現,能夠經過idea的工具,對Kotlin文件進行反編譯:
Tools ->Kotlin -> Show Kotlin Bytecode -> 右側彈出字節碼框 ->左上角 Decompile按鈕
在Kotlin中,當你聲明屬性的時候,也就聲明瞭對應的訪問器(即get和set)
val屬性只有一個getter,var屬性既有 getter 和 setter。 聲明一個屬性的完整語法:
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
複製代碼
其中,初始化器,getter 和 setter 都是可選的。若是類型能夠從初始化器或者getter 返回值中推斷出來,也能夠省略。 訪問器的默認實現很是簡單,即對對應變量的返回和更改。
當須要在值被訪問或修改時提供額外的邏輯,能夠經過自定義getter和setter
在Kotlin中的實現
class Rectangle(val height:Int,val width:Int){
val isSquare:Boolean
get(){
return height == width
}
}
複製代碼
對應的Java實現:
在Kotlin中實現:
class Rectangle(val height:Int,val width:Int){
var isSquare:Boolean = false
set(value) {
field = value
}
}
複製代碼
在setter方法中,使用特殊的標識符field來訪問支持字段(幕後字段)的值。具體幕後字段後面再說。
Kolin中,名稱以is開頭的變量。轉換成對應的Java get 和 set 方法時,getter不會添加任何的前準,setter名稱中的is會被替換成set。
class Person(
var isDaqi:Boolean = false
)
複製代碼
該對象在Java中的訪問器爲:
Kotlin中 while 和 do-while循環,其語法與Java的基本沒區別。
而for循環僅以一種形式存在,和for-each差很少。但用 in 取代了 :
fun iterationArray(args:Array<String>){
for (str in args) {
}
}
複製代碼
for循環還能夠遍歷區間。區間本質上是兩個值之間的間隔。使用..運算符表示區間。
Kotlin中的區間是閉合區間,即結束值也是區間的一部分。而區間默認迭代步長爲1。
val oneToTen = 1..10
複製代碼
能夠經過step關鍵字修改步長。遍歷時,i變量其增加幅度將變爲2,即每次迭代時都會自增2。
for(i in 0..100 step 2){
}
複製代碼
若是想要一個半閉合區間,即結束值不屬於區間的一部分,可使用until關鍵字,
val oneToNine = 1 until 10
複製代碼
若是須要一個倒序的區間,可使用downTo關鍵字
val tenToOne = 10 downTo 1
複製代碼
此時,將從10一直遞減到1進行循環。downTo表示的區間也是一個閉合區間。
若是想實現普通for循環同樣,對數據索引進行循環,可使用數組的indices變量
for (i in args.indices) {
println(args[i])
}
複製代碼
在Kotlin中,if是一個表達式,即它會返回一個值。
if的分支爲代碼塊時,最後的表達式將做爲該代碼塊的值:
val max = if (a > b) {
print("Choose a")
a
} else {
print("Choose b")
b
}
複製代碼
Kotlin中的when,對應的是Java中的switch,但比起更增強大。
when 將它的參數與全部的分支條件按順序比較,直到某個分支知足條件,執行其分支對應的代碼。當多分支須要用相同的方式處理時,能夠把其放在一塊兒,用逗號分隔。
當when做爲表達式使用時,必須有 else 分支, 除非編譯器檢測出全部的可能狀況都已經被覆蓋。(例如枚舉類)
when (x) {
0, 1 -> print("x == 0 or x == 1")
2 -> print("x == 2")
else -> print("otherwise")
}
複製代碼
有沒有發現,沒有了那繁瑣的case和break!!
when的參數無關緊要,而且無限制類型!並且能夠用任意表達式做爲分支條件。(switch要求必須使用常量做爲分支條件~)
when做爲表達式函數的的函數體,直接使用函數的參數,自身並沒有設置參數。並在條件語句中使用in或者!in 判斷一個變量是否在區間或者集合中。
fun daqi(num:Int,intArray: IntArray) = when{
num in 1..10 -> "1~10"
num !in intArray -> "no in Array"
else -> "other"
}
複製代碼
when 也能夠用來取代 if-else if鏈.
fun daqi(num:Int) = when{
num < 0 -> "小於0"
num >0 && num < 10 -> "1..10"
else -> "other"
}
複製代碼
is能夠檢查一個變量是不是某種類型,再配合智能轉換(檢查過某個變量的類型後,再也不須要再轉換它,直接能夠把它看成檢查過的類型使用)能夠很方便的對進行類型安全操做。
//Any相似於Java的Object
fun daqi(num:Any) = when(num){
is String -> {
//此時num已經爲String類型
println("該變量類型爲String,獲取其長度")
println(num.length)
}
is Int -> {
//此時num已經爲Int類型
println("該變量類型爲Int,將其與10進行對比")
num.rangeTo(10)
}
else -> "other"
}
複製代碼
Kotlin的異常處理與Java相似。當拋出異常時,不須要使用new關鍵字建立異常實例。
var daqi:String? = null
if (daqi == null){
throw NullPointerException("daqi is null")
}
複製代碼
try也能夠做爲表達式,將其賦值給變量。當代碼執行正常,則try代碼塊中最後一個表達式做爲結果,若是捕獲到異常,對應catch代碼塊中最後一個表達式做爲結果。finally 塊中的內容不會影響表達式的結果。
fun readNumber(reader:BufferedReader):Int? = try{
Integer.parseInt(reader.readLine())
}catch(e:NumberFormatException){
null
}catch (e:NullPointerException){
null
}finally {
reader.close()
}
複製代碼
能夠有0到多個 catch 塊。finally 塊能夠省略。 可是 catch 與 finally 塊至少應該存在一個。
kotlin中用兩個關鍵字enum和class聲明枚舉類。enum是一個軟關鍵字,只有當它出如今class前面時纔有特殊的意義。
聲明普通枚舉類:
enum class Color{
RED,BLUE
}
複製代碼
聲明帶屬性的枚舉類:
enum class Color(val r:Int,val g:Int,val b:Int){
RED(255,0,0),BLUE(0,0,255);
fun rgb = (r * 256 + g) * 256 + b
}
複製代碼
若是在枚舉類型中定義任何方法,須要使用分號;把枚舉常量列表和方法定義分開。