Kotlin基本語法和使用技巧

基本語法

val value: String? = "HelloWorld"
val name: String = getName() ?: return  //若是是null就return
println("$arg1 + $arg2 = ${arg1 + arg2}")    //字符串模板
val FINAL_HELLO_CHINA = "HelloChina"   //類型能夠不寫,自動推導
val args1 = arrayOf(1,2,3)
val range: IntRange = 0..1024 // [0, 1024]
val range_exclusive: IntRange = 0 until 1024 // [0, 1024) = [0, 1023]
    
class A {
    var b = 0
    lateinit var c: String   //var延遲初始化用lateinit,使用 lateinit 關鍵字,變量在定義時不須要初始化,因此在使用questionTextView變量時,不須要加上 ? 和 !! 操做符。在使用第一次變量以前,必定要保證爲questionTextView賦值 , 否則會出現空指針異常。
    lateinit var d: X
    val e: X by lazy {
        //val延遲初始化用lazy代理
        println("init X")
        X()
    }
    
    //第一次調用 get() 會執行已傳遞給 lazy() 的 lambda 表達式並記錄結果, 後續調用 get() 只是返回記錄的結果。
     private val linearLayoutManager by lazy {
        LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
    }
    
    var cc: String? = null //初始化成null很差
}
abstract class Person(open val age: Int) {
    //只有open的成員和類才能被繼承,接口和抽象類默認是open的
    abstract fun work()
}

//沒有三目運算符,可使用if 表達式
val max = if (a > b) a else b

//對於bean對象能夠這樣寫
data class Forecast(val date: Date, val temperature: Float, val details: String)
    
//Kotlin 的構造函數能夠寫在類頭中,跟在類名後面
class Person( var name:String){

    private var description: String? = null

    //在主構造函數中不能有任何代碼實現,若是有額外的代碼須要在構造方法中執行,你須要放到init代碼塊中執行
    init {
        name = "Zhang Tao"
    }

    internal fun sayHello() {
        println("hello $name")
    }

    fun printName(){
        println(name)
    }

    //這裏咱們讓次級構造函數調用了主構造函數,完成 name 的賦值。
    // 因爲次級構造函數不能直接將參數轉換爲字段,因此須要手動聲明一個 description 字段,併爲 description 字段賦值。
    constructor(name: String, description: String) : this(name) {
        this.description = description
    }

}

class Latitude private constructor(val value: Double) {
        companion object {//伴隨對象
            //加上這個註解Java能夠直接像靜態那樣調用,不然得Latitude.companion.ofDouble(3.0)
            @JvmStatic
            fun ofDouble(double: Double): Latitude {
                return Latitude(double)
            }

            fun ofLatitude(latitude: Latitude): Latitude {
                return Latitude(latitude.value)
            }

            @JvmField
            val TAG: String = "Latitude"
        }
    }

    class Manager : Driver, Writer {
        override fun write() {

        }

        override fun drive() {

        }
    }

  

//擴展方法,不用運算符operator的話,用"abc".times(16)這樣來調用,jva能夠類名.times("abc", 16)調用
    operator fun String.times(int: Int): String {
        val stringBuilder = StringBuilder()
        for (i in 0 until int) {
            stringBuilder.append(this)
        }
        return stringBuilder.toString()
    }

//函數引用
    val pdfPrinter = PdfPrinter()
        args.forEach(pdfPrinter::println)
        
         class PdfPrinter {
        fun println(any: Any) {
            kotlin.io.println(any)  //重名了能夠用包名調用
        }
    }

   //常見的高階函數
        val list = listOf<Int>(1, 2, 3, 5, 10, 8, 2)
        val newList = ArrayList<Int>();
        list.forEach {
            val newElement = it * 2 + 3
            newList.add(newElement)
        }
        //和上面同樣,上面麻煩,map能夠對集合進行操做,返回一個修改過得集合
        //flatmap,對集合的集合進行操做,省去了倆次遍歷的麻煩
        val newList2 = list.map { it * 2 + 3 }
        val newList3 = list.map { Int::toDouble }
        newList3.forEach(::println)
        newList3.map(::println)  //和上面輸出同樣,可是又從新add了一個集合,很差,純粹用於迭代的話會影響性能,實現裏面還有一個數組
        
        //提取開頭指定數量或符合指定條件的子集  
        list.takeWhile { it <= 3 }.forEach(::println)  //小於的去掉
        list.forEach {
            if (it % 2 == 0) {
                println(it)
            }
        }
        list.filter { it.isEvent() }.forEach(::println)//過濾
            
        val person = findPerson();
        //person是可null的,因此須要?
        println(person?.age)
        println(person?.name)
        //上面太麻煩,findPerson加了?,因此後面不須要了,減小的判空操做。let能夠安全調用
        findPerson()?.let { person ->
            person.work()
            println(person.age)
        }
        //還能夠更簡潔,person也不用寫
        findPerson()?.apply {
            work()
            println(age)
        }
//使用apply作對象的初始化
return TextView(context).apply {
    text = "test"
    setOnClickListener(onClickListener)
}

    //use不用close了
        BufferedReader(FileReader("hello.txt")).use {
            var line: String?
            while (true) {
                //it表示當前對象BufferedReader,因此能夠用它的方法
                line = it.readLine() ?: break
                println(line)
            }
        }

使用技巧

take是從集合中取前幾個元素
takeLast是從集合中取後幾個元素
sortedBy 排序
過濾list,符合過濾條件的就是過濾結果
filterNot把符合條件的過濾掉,剩下的是結果。這個操做和 filter 相反
slice,取集合中的某一部分java

val numbers = listOf("one", "two", "three", "four", "five", "six")    
println(numbers.slice(1..3))
println(numbers.slice(0..4 step 2))
println(numbers.slice(setOf(3, 5, 0))) 

[two, three, four]
[one, three, five]
[four, six, one]

val numbers = listOf("one", "two", "three", "four", "five", "six")
println(numbers.takeWhile { !it.startsWith('f') })
println(numbers.takeLastWhile { it != "three" })
println(numbers.dropWhile { it.length == 3 })
println(numbers.dropLastWhile { it.contains('i') })


[one, two, three]
[four, five, six]
[three, four, five, six]
[one, two, three, four]
  • 擴展函數(相似於工具類)
fun toast(message: String, length: Int = Toast.LENGTH_SHORT) {
        Toast.makeText(this, message, length).show()
    }
   
   toast("hello")
   
    //擴展函數,咱們就能夠在每個Activity中直接使用toast()函數了。
    fun Context.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
        Toast.makeText(this, message, duration).show()
    }

!! 強⾏行行調⽤用符
?. 安全調⽤用符api

  • kotlin默認不能空,變量類型後面跟?號定義,代表這是一個可空類型
  • ?. 表明着若是該類型爲空的話就返回null不作後續的操做,若是不爲空的話纔會去訪問對應的方法或者屬性
  • !!. 表明着若是該類型爲空的話就拋出NullPointerException,若是不爲空就去訪問對應的方法或者屬性, 因此只有在不多的特定場景才用這種符號,表明着程序不處理這種異常的case了,會像java代碼同樣拋出NullPointerException。 並且代碼中必定不用出現下面這種代碼,會讓代碼可讀性不好並且若是有空指針異常,咱們也不能立刻發現是哪空了:
/*
    * 不推薦這樣的寫法:鏈式的連續用!!.
    * */
    val user = User()
    user!!.name!!.subSequence(0,5)!!.length

在 Kotlin 中建立單例不用像 Java 中那麼複雜,只須要把 class 換成 object 就能夠了。數組

object Sample {    val name = "A name"}

//餓漢式的單例,而且實現了線程安全
object A {  
val number: Int = 1   、
fun method() {       
println("A.method()")   
  }
}

companion 能夠理解爲伴隨、伴生,表示修飾的對象和外部類綁定。相似靜態變量
寫在頂級的函數(不須要在class裏寫方法)或者變量有個好處:在 Android Studio 中寫代碼時,IDE 很容易根據你寫的函數前幾個字母自動聯想出相應的函數。這樣提升了寫代碼的效率,並且能夠減小項目中的重複代碼。
若是想寫工具類的功能,直接建立文件,寫 top-level「頂層」函數。安全

建立數組,增長不少有用的工具函數
contains()first()find()app

val strs: Array<String> = arrayOf("a", "b", "c")

循環經過標準函數 repeat()ide

repeat(100) {
// todo
}

map也能夠這樣建立函數

val map = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 3)

listOf() 建立不可變的 List,mutableListOf() 建立可變的 List工具

Kotlin 中集合分爲兩種類型:只讀的和可變的。這裏的只讀有兩層意思:
集合的 size 不可變
集合中的元素值不可變
能夠轉換性能

map.toMutableMap()

構造器ui

class User constructor(var name: String) {                                   // 直接調用主構造器    
constructor(name: String, id: Int) : this(name) {    }                //  經過上一個次構造器,間接調用主構造器  
constructor(name: String, id: Int, age: Int) : this(name, id) {      }
}

forEach:遍歷每個元素
filter:對每一個元素進行過濾操做,若是 lambda 表達式中的條件成立則留下該元素,不然剔除,最終生成新的集合
map:遍歷每一個元素並執行給定表達式,最終造成新的集合
flatMap:遍歷每一個元素,併爲每一個元素建立新的集合,最後合併到一個集合中

Elvis 操做符
經過 ?: 的操做來簡化 if null 的操做

fun validate(user: User) {   
val id = user.id ?: return 
// 驗證 user.id 是否爲空,爲空時 return 
}
// 等同於
fun validate(user: User) {    
if (user.id == null) {        
return   
}    
val id = user.id
}

== :能夠對基本數據類型以及 String 等類型進行內容比較,至關於 Java 中的 equals
=== :對引用的內存地址進行比較,至關於 Java 中的 ==

若是每一個類型都去實現諸如 TextViewList、ActivityList 這樣的具體的類型,顯然是不可能的。所以就誕生了「泛型」,它的意思是把具體的類型泛化,編碼的時候用符號來指代類型,在使用的時候,再肯定它的類型

使用關鍵字 out 來支持協變,等同於 Java 中的上界通配符 ? extends。
使用關鍵字 in 來支持逆變,等同於 Java 中的下界通配符 ? super。

var textViews: List<out TextView>
var textViews: List<in TextView>

Kotlin 標準函數
使⽤用時能夠經過簡單的規則做出一些判斷

  • 返回⾃自身
    從 apply 和 also 中選
    做⽤域中使⽤ this 做爲參數選擇 apply
    做⽤域中使⽤ it 做爲參數選擇 also
  • 不須要返回⾃自身
    從 run 和 let 中選擇
    做用域中使用 this 做爲參數,選擇 run
    做用域中使用 it 做爲參數,選擇 let

apply 適合對一個對象作附加操做的時候
let 適合配合空判斷的時候
with 適合對同一個對象進行屢次操做的時候

協程就是kotlin官方提供的線程api

屬性委託
有些常見的屬性操做,咱們能夠經過委託方式,讓它實現,例如:lazy 延遲屬性: 值只在第一次訪問的時候計算
類委託
能夠經過類委託來減小 extend類委託的時,編譯器回優使用自身從新函數,而不是委託對象的函數

interface Base{
fun print()
}

case BaseImpl(var x: Int):Base{

override fun print(){
print(x)
}

}
// Derived 的 print 實現會經過構造函數的b對象來完成class Derived(b: base): Base by b

委託就是代理

//接口代理,能夠不是必須實現接口或抽象類的方法
    class SeniorManager(val driver: Driver, val writer: Writer) : Driver by driver, Writer by writer

    class CarDriver : Driver {
        override fun drive() {
            println("開車呢")
        }
    }

    class PPTWriter : Writer {
        override fun write() {
            println("作PPT呢")
        }

    }

    interface Driver {
        fun drive()
    }

    interface Writer {
        fun write()
    }
    

        val driver = CarDriver()
        val writer = PPTWriter()
        val seniorManager = SeniorManager(driver, writer)
        seniorManager.drive()
        seniorManager.write()
            
  //類委託
    interface Base {
        fun print()
    }
    class BaseImpl(val x: Int) : Base {
        override fun print() { print(x) }
    }
    class Derived(b: Base) : Base by b//實現繼承的代替方式
    fun main(args: Array<String>) {
        val b = BaseImpl(10)
        Derived(b).print() // prints 10
    }

使用 類名::class 獲取的是 Kotlin 的類型是 KClass 使用 類名::class.java 獲取的是 Java 的類型 Any Kotlin 的頂層父類是 Any ,對應 Java 當中的 Object ,可是比 Object 少了 wait()/notify()等函數 Unit Kotlin 中的 Unit 對應 Java 中的 void 在 Java 中經過 「類名.this」 獲取目標類引用 在 Kotlin 中經過「this@類名」獲取目標類引用

相關文章
相關標籤/搜索