Kotlin語言入門學習(二)

 

本篇文章是對Kotlin語言入門學習(一)的補充,適用於有一定Java基礎的同學學習,在理解Kotlin的基本語法結構後,更重要的是加以實踐,方便更快更好的理解Kotlin語言。

 


一、Kotlin是什麼
Kotlin是一種基於JVM的靜態類型編程語言
Kotlin的入口是main()函數


Kotlin的特點:
1,極簡:語法簡潔優雅,類型系統中一切皆引用
2,空安全:?可空
3,多範式:Kotlin同時支持OOP與FP編程範式
4,可擴展:Kotlin可直接擴展函數與屬性
5,高階函數與閉包
6,支持快速實現DSL
7,智能推斷


Kotlin的工具平臺:雲端IDE,命令行REPL,IDEA

 

二、Kotlin語法基礎

throw表達式:在Kotlin中,throw是表達式,它的類型是特殊類型Nothing。該類型沒有值,與C、Java中的void意思一樣


Kotlin中有兩種類型的相等性:
引用相等===  !==  (兩個引用指向同一對象,即值與引用都相等)
結構相等== !=  (使用equals()判斷,比較值)


Elvis操作符  ?:   在Kotlin中,Elvis操作符特定是跟null進行比較,如:y = x?:0   等價於:val y = if(x!==null) x else 0
 

非空斷言“!!”
Kotlin提供了斷言操作符“!!”,使得可空類型對象可以調用成員方法或者屬性(但遇見null,就會導致空指針異常)
Kotlin中沒有三元表達式,對應的是:if...else語句,如:if(true) 1 else 0。而Elvis操作符是精簡版的三元運算符


三、類型系統與可空類型


3.1類型系統
相對於Java語言,Kotlin語言去掉了原始數據類型,只有包裝類型
Kotlin系統類型分爲可空類型和不可空類型


Kotlin在類型T後面加個“?”,就表達了可空類型
                  fun main(args:Array<String>){
                        println(strLength(null))
                        println(strLength("abc"))
                  }
                 fun strLength(s:String?):Int{
                        return s?.length ?:0  //?.是安全調用符,?:是Elvis操作符
                 }          
 

3.2特殊類型
Unit、Nothing、Any及其對應的可空類型Unit?、Nothing?、Any?
當一個函數沒有返回值的時候,用Unit來表示這個特徵,而不是null,但大多數時候,可省略,返回類型是Unit
Void對應Nothing?,其唯一可被訪問的返回值是null


如果一個函數的返回值是Nothing,意味着這個函數永遠不會有返回值
Any?是可空類型層次的根,Any是非空類型層次結構的根,Any?是Any的超集,Any?是Kotlin類型層次結構的最頂端


3.3類型檢測與類型轉換
Kotlin中的is和!is類似於Java中的instanceOf,類型匹配
as運算符用於類型轉換,as?爲可空轉換,如果類型不兼容,則返回null
在Kotlin中,父類是禁止轉換爲子類的

 

四、類與面向對象編程

 

Kotlin中沒有靜態屬性和方法,但可以使用關鍵字object聲明一個object單例對象,Kotlin中還提供了伴生對象,用companion object關鍵字聲明
數據類:只存儲數據,不包含操作行爲的類,Kotlin中使用關鍵字data class可創建一個只包含數據的類,類似於Java中的bean類

 

五、函數與函數式編程

5.1函數式編程
函數式編程(FP),使一種編程範式,即面向函數編程,核心思想在於解決問題的過程,把任務分解爲一個個的函數,最後通過函數組合來實現目標


比如,我們現在有一個字符串列表:val strList = listOf("a","ab","abc","abcd","abcde","abcdef","abcdefg")
現在我們想要過濾出字符串元素中長度是奇數的列表,那麼可以把這個問題的解決邏輯拆成兩個函數來組合實現:
             val f = fun (x:Int) = x % 2 == 1     //判斷輸入的Int是否奇數
             val g = fun (s:String) = s.length    //返回輸入的字符串參數的長度
再使用函數h來封裝:
             val h = fun (g:(String) -> Int,f:(Int -> Boolean):(String) -> Boolean){
                        return{ f(g(it)) }
              }
這個h函數稍顯長,可通過類型別名typealias使代碼更簡潔

 

5.2Kotlin中的特殊函數
特殊函數主要有:run()、apply()、let()、also()、with()


run():使用時可使用run(其它函數),表示執行()內的函數,()可省略


apply():通過.方式調用,表示在run()的基礎上返回當前調用者對象


let():通過.方式調用,表示把當前調用對象作爲參數傳給let函數,如myfun().let{println(it)},則表示執行完myfun函數後,返回這傳給let()函數,最後打印結果爲myfun()返回值


also():通過.方式調用,表示在let()基礎上返回當前調用者


with():執行傳入的代碼塊,或者理解爲接收一個指定類型的對象去執行body函數

 

以上5種函數沒有給出具體示例,希望讀者找相關例子進行更好的理解並在實踐中加以應用

 

六、擴展函數

 

爲List擴展一個filter()函數
            fun <T> List<T>.filter(predicate: (T) -> Boolean):MutableList<T>{
                         val result = ArrayList<T>()
                         this.forEach{
                               if(predicate(it)){
                                          result.add(it)
                               }
                         }                         
                  return result
            }

 

調用:
             val list = mutableListOf(1,2,3,4,5,6,7)
             val result = list.filter{
                   it%2==1
             }
             predicate(result)     //[1,3,5,7]

 

擴展屬性:允許定義在類或者Kotlin文件中,不允許定義在函數中

 

七、集合類
集合類存放的都是對象的引用,而非對象本身,Kotlin中集合類分爲:可變集合類(Mutable)與不可變集合類(Immutable)
遍歷集合中的元素:forEach
             list.forEach{
                      println(it)
             }


映射函數map:
             val list = listOf(1,2,3,4,5,6,7)  //聲明並初始化一個List
             list.map{it*it}     //map函數對每個元素進行乘方操作,返回[1,4,9,16,25,36,49]
             set和map類似

過濾函數filter:
             data class Student(var id:Long,var name:String,var age:Int,var score:Int){  //聲明Student數據類
                              override fun toString():String{  //覆寫toString()函數
                                            return "Student(id = $id,name = '$name',age = $age,score = $score)"
                              }
             }
創建一個持有Student對象的List
             val studentList = listOf(
                   Student(1,"Jack",18,90),
                   Student(2,"Rose",17,90),
                   Student(3,"Alice",16,70),
             )
此時,如果我們想要過濾出大於等於18歲的學生,可以這樣寫:
             studentList.filter{it.age>=18}
輸出結果:[Student(id = 1,name = "Jack",age = 18,score = 90)]


排序函數:
            reversed()倒序
            sorted()升序
元素去重:

           distinct()

 

八、泛型
類型上界
fun <T:Comparable<T>> gt(x:T,y:T):Boolean  //T的類型上界是Comparable<T>,即告訴編譯器,類型參數T代表的都是實現了Comparable接口的類,這樣等於告訴編譯器,它們都實現了CompareTo方法。
如果沒有上界聲明,則無法直接使用CompareTo操作符

 

out T 等價於 ? extend T  指定類型參數的上界
in T  等價於 ? super T  指定類型參數的下界

 

九、文件I/O操作、正則表達式與多線程
Kotlin的序列化直接採用了Java序列化類的類型別名
internal typealias Serializable = java.io.Serializable

 

Kotlin中常用的文件讀寫API:
File.readText()  //讀取該文件的所有內容作爲一個字符串返回
File.readLines()  //讀取該文件的每一行內容,存入一個List返回
File.readBytes()  //讀取文件所有內容以ByteArray的方式返回
File.writeText()  //覆蓋寫入text字符串到文件中
File.writeBytes()  //覆蓋寫入ByteArray字節流數組
File.appendText()  //在文件末尾追加寫入text字符串
File.appendBytes()  //在文件末尾追加寫入ByteArray字節流數組

 

9.1遍歷文件樹
遍歷文件樹:walk函數
下面的例子遍歷了指定文件夾下的所有文件
                  fun traverseFileTree(filename:String){
                        val f = File(filename)
                        val fileTreeWalk = f.walk()  //調用walk()會返回一個FileTreeWalk對象
                        fileTreeWalk.iterator().forEach{
                                             println(it.absolutePath)
                        }                   
                   } 

 

9.2遞歸複製文件
複製該文件或者遞歸該目錄及其所有子文件到指定目錄下,如果指定路徑下的文件不存在,會自動創建
copyRecursively函數簽名:
                  fun File.copyRecursively{
                               target:File,  //目標文件
                               overrite:Boolean = false  //是否覆蓋
                               onError:(File,IOException) -> OnErrorAction = { _,exception -> throw exception})  //錯誤處理
                   }:Boolean
 
 9.3網絡I/0
 readBytes和readText
 使用這兩個方法配合正則表達式實現網絡爬蟲功能:
 根據URL獲取該URL的響應HTML函數:
                 fun getUrlContent(url:String):String{
                           return URL(url).readText(Charset.defaultCharset())  //獲取該URL的響應HTML文本
                 }
 根據URL獲取該URL的響應比特數組函數
                fun getUrlBytes(url:String):ByteArray{
                          return URL(url).readBytes  //獲取該URL的響應ByteArray
                }
 把URL響應字節數組寫入文件中
               fun writeUrlBytesTo(filename:String,url:String){
                          val bytes = URL(url).readBytes()
                          File(filename).writeBytes(bytes)  //寫入文件
               }
 


 9.4正則表達式
 構造Regex表達式
 val r1 = Regex("[a-z]+")  //創建一個Regex對象,匹配的正則表達式是[a-z]+
 val r2 = "[a-z]+".toRegex()  //直接使用Kotlin中給String擴展的toRegex函數
 
 Regex函數:
 mataces()  //輸入字符串全部匹配
 containMatchIn()  //輸入字符串至少有一個匹配
 matchEntrie()  //輸入字符串全部匹配,返回一個匹配結果對象
 replace()  //把輸入字符串中匹配的部分替換成replacement的內容//把輸入字符串中匹配到的值,用函數transform映射之後的新值替換
 find()  //返回輸入字符串中第一個匹配的值
 findAll()  //返回輸入字符串中所有匹配的值MatchResult的序列 

 

同步方法和塊:
synchronized不是Kotlin中的關鍵字,它替換爲@Sychronized註解
同樣的,Kotlin中沒有volalile關鍵字,但是有@Volatile註解

 

參考:《Kotlin從入門到進階實戰》  ——陳光劍

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