法国波尔多酒庄有哪些: Kotlin 常用語法篇

0
回復
58
查看
打印 上一主題 下一主題
[復制鏈接]

恋恋波尔多 www.luaogj.com.cn 8

主題

13

帖子

572

安幣

代碼手工藝人

Rank: 4

習慣用法和規范類布局
通常,一個類的內容按以下順序排列:
  • 屬性聲明與初始化塊
  • 次構造函數
  • 方法聲明
  • 伴生對象
不要按字母順序或者可見性對方法聲明排序,也不要將常規方法與擴展方法分開。而是要把相關的東西放在一起,這樣從上到下閱讀類的人就能夠跟進所發生事情的邏輯。選擇一個順序(高級別優先,或者相反) 并堅持下去。
將嵌套類放在緊挨使用這些類的代碼之后。如果打算在外部使用嵌套類,而且類中并沒有引用這些類,那么把它們放到末尾,在伴生對象之后。
常量名稱
標有 const 的屬性,或者 val 屬性的對象應該使用大寫、下劃線分隔的名稱:
const val MAX_COUNT = 8  //const屬于編譯期常量val USER_NAME_FIELD = "UserName"
保存帶有行為的對象或者可變數據的頂層/對象屬性的名稱應該使用常規駝峰名稱:
val mutableCollection: MutableSet<String> = HashSet()
保存單例對象引用的屬性的名稱可以使用與 object 聲明相同的命名風格:
val PersonComparator: Comparator<Person> = ...Lambda 表達式參數
在簡短、非嵌套的 lambda 表達式中建議使用 it 用法而不是顯式聲明參數。而在有參數的嵌套 lambda 表達式中,始終應該顯式聲明參數。
在 lambda 表達式中返回
避免在 lambda 表達式中使用多個返回到標簽。請考慮重新組織這樣的 lambda 表達式使其只有單一退出點。 如果這無法做到或者不夠清晰,請考慮將 lambda 表達式轉換為匿名函數。
不要在 lambda 表達式的最后一條語句中使用返回到標簽。
data數據類data class User(val name: String, val age: Int)
Kotlin編譯器會自動從主構造函數中聲明的所有屬性并會為User類提供以下功能:
所有屬性的 getters (對于 var 定義的還有 setters)
  • equals()
  • hashCode()
  • toString()
  • copy()
為了確保數據類生成的代碼的一致性,一般滿足主構造函數需要至少有一個參數,主構造函數的所有參數需要標記為 val 或 var,而且數據類不能是抽象、開放、密封或者內部的
請注意,對于那些自動生成的函數,編譯器只使用在主構造函數內部定義的屬性。如需在生成的實現中排出一個屬性,請將其聲明在類體中:
data class Person(val name: String) {var age: Int = 0}
在 toString()、 equals()、 hashCode() 以及 copy() 的實現中只會用到 name 屬性,并且只有一個 component 函數 component1()。雖然兩個 Person 對象可以有不同的年齡,但它們會視為相等。
復制
在很多情況下,我們需要復制一個對象改變它的一些屬性,但其余部分保持不變。 copy() 函數就是為此而生成。對于上文的 User 類:
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)
我們可以寫成:
val jack = User(name = "Jack", age = 1)val olderJack = jack.copy(age = 2)過濾 listval positives = list.filter { x -> x > 0 }
或者可以更短:
val positives = list.filter { it > 0 }
遍歷 map/pair型list
val map = hashMapOf("name" to "zhangsan","age" to "26","address" to "hangzhou")   for ((k, v) in map) {        println("$k -> $v")        println("$k -> ${map[k]}")   }map的訪問支持 map[key]形式
k、v 可以改成任意名字。
“if”表達式fun foo(param: Int) { val result = if (param == 1) {    "one"   } else if (param == 2) {     "two"  } else {    "three"  }}使用條件語句
優先使用 try、if 與 when 的表達形式。例如:
return if (x) foo() else bar() return when(x) { 0 -> "zero"else -> "nonzero"}
優先選用上述代碼而不是:
if (x)   return foo()else   return bar() 復制代碼when(x) {      0 -> return "zero"      else -> return "nonzero"}
注:二元條件優先使用 if 而不是 when,如果有三個或多個選項時優先使用 when。
對一個對象實例調用多個方法 (with)class Turtle {    fun penDown()    fun penUp()    fun turn(degrees: Double)    fun forward(pixels: Double)}val myTurtle = Turtle()    with(myTurtle) { // 畫一個 100 像素的正方形       penDown()       for(i in 1..4) {       forward(100.0)       turn(90.0)       }      penUp()}對象聲明
Kotlin中object關鍵字在多種情況下出現,包括下面講到的“伴生對象”,“對象表達式”以及現在講的“對象聲明”都使用了object關鍵字,可見object關鍵字用法多么廣發和強大;
object關鍵字出現他們都遵循同樣的核心理念:這個關鍵字定義了一個類,并創建了該類的實例,也就是說用object關鍵字在定義該類的同時創建了該類的對象;
在開發中我們通?;崾褂玫降ダJ?,java中單例通過static字段存儲實例對象,并將構造私有化,通過暴露出一個靜態方法用來唯一訪問實例,在kotlin中可以直接通多object聲明這樣的一個類,通過這種“對象聲明”方式將類的聲明和類的唯一實例結合在一起。
與類聲明一樣,一個對象聲明同樣可以包括屬性,方法,初始化語句塊等聲明,唯一不允許的是構造方法,與普通類實例不同,對象聲明在定義的時候就已經被創建,不需要在其他地方調用構造方法;
object Persion{fun add(var a : Int , var b:Int):Int{return a+b}}val sum=Persion.add(3,5) //單例調用伴生對象
伴生對象也叫類內部的對象,其聲明可以用 companion 關鍵字標記:
class MyClass {    companion object Factory {        fun create(): MyClass = MyClass()    }}
可以省略伴生對象的名稱,在這種情況下將使用名稱 Companion:
class MyClass {     companion object { }}val x = MyClass.Companion
注意:伴生對象的成員看起來像java中的靜態成員,在運行時他們仍然是真實對象的實例成員,而且,例如還可以實現接口:
interface Factory<T> {    fun create(): T}class MyClass {      companion object : Factory<MyClass> {          override fun create(): MyClass = MyClass()       }}val f: Factory<MyClass> = MyClass
當然,在 JVM 平臺,如果使用 @JvmStatic 注解,你可以將伴生對象的成員生成為真正的靜態方法和字段。
對象表達式
object關鍵字不僅可以用來聲明一個單例對象、伴生對象,也可以用來聲明一個匿名對象,匿名對象替代java中的匿名內部類的用法。
button.setOnClickListener(object: View.OnClickListener(){ override fun OnClick(v:View){}})
除了去掉了對象名字以外,語法與對象聲明相同,對象表達式聲明了一個類并創建了該類的實例,但并沒有為這個類或實例分配一個名字,通常來講,他們都不需要一個名字,因為你會將這個對象作為一個函數的參數,如果需要分配一個名字給這個對象,你可以將這個對象存儲到一個變量中:
val listener=object: View.OnClickListener(){ override fun OnClick(v:View){}}
與java的匿名對象不同的是,java匿名對象只能擴展一個類或者實現一個接口,kotlin的對象表達式可以實現多個接口或者不實現接口。
需要注意的是,Kotlin的對象表達式并不是單例類型的,每次執行到該位置時候,就會重新創建一個新的實例。
例外與java最大不同是kotlin的對象表達式中可以訪問被創建函數中的局部變量,但是在java中訪問被限制在final類型變量上,但是kotlin中解除了這個限制,這就代表kotlin中對象表達式可以訪問并修改被創建函數的局部變量,
button.setOnClickListener(object: View.OnClickListener(){var count=0override fun OnClick(v:View){count++}})Lambda 表達式
作為函數參數的代碼塊, lambda表達式通常作為一個參數傳入函數中,也可以單獨存儲到一個變量中; 在java 8 中jdk 中也支持了lambda編程風格,這也是java 語言在不斷演變和優化中最讓人望眼欲穿的功能, 那么使用lambda到底能帶來那些有優勢呢?
java中最普通的點擊監聽器實現:
button.setOnClickListener(new View.OnClickListener(){@overridepublic void OnClick(View view){// todo}})
通過匿名內部類去傳入一個監聽器實例,并實現監聽器的click方法,當我們有多個view需要實現這種點擊實現,那我們就得寫多個這種實現,雖然寫起來很簡單,但是確實為我們增加了代碼量,無論從語言角度還是設計模式角度看待這個問題,良好的編程風格主要原則之一就是避免代碼在任何地方重復, 那么lambda表達式就很好解決這個問題, kotlin和java8 之后實現是:
button.setOnClickListener{  // todo  }
這段代碼和java匿名內部類做了同樣的事情,但是更加簡單易讀,lambda被當作只有一個方法的匿名對象的替代品使用;
lambda同樣跟集合搭配使用是kotlin 的一大特色,如找到一個list 中年齡最大的persion,在java中普遍實現是你會引入兩個中間變量,一個用來保存最大年齡,而另一個用來保存最大年齡的人,然后遍歷這個列表,不斷更新這兩個變量:
public void findMaxAgePersion(List<Persion> persions){int maxAge=0Persion oldPersion=nullforEach(Persion persion:persions){if(persion.age>maxAge){maxAge=persion.ageoldPersion=persion}}println(oldPersion)}List persions=new ArrayList<Persion>()persions.add(new Persion("zhangli",16))persions.add(new Persion("wangpeng",22))findMaxAgePersion(persion)
Kotlin中實現:
val persions=listOf(Persion("zhangli",16),Persion("zhangpeng",26))val persion=persions.maxBy{it.age}println(persion)
我們通常在java中對集合做的大多數事情可以通過使用lambda或成員引用的庫函數來更好的表達,這樣代碼就少很多,也變得更容易理解;
lambda語法結構:{x:Int, y:Int -> x+y }
Kotlin的lambda表達式始終用花括號包圍,花括號中通過 箭頭(->)將實參和函數體分開,
val sum={x:Int, y:Int -> x+y }println(sum(3, 5)) // lambda表達式存儲到變量中,可以當做普通函數通過實參正常調用
Kotlin中對lambda有些語法約定:
  • 如果lambda表達式作為函數最后一個實參,可以將lambda表達式放到括號外面;
  • 當lambda作為函數唯一的一個實參時,可以將函數括號直接省略;
  • 當有多個實參時候,即可以選擇把lambda留在括號內強調它是一個實參,也可以放到括號外邊;
  • 當函數有多個lambda實參需要傳入,不能超過一個lambda表達式放到外面;
我們拿上面的persions.maxBy{it.age}案例來說:
亦可以寫成:
    persions.maxBy({persion:Persion -> persion.age})
作為最后一個參數,可將lambda放到括號外邊:
   persions.maxBy(){ persion:Persion -> persion.age }
作為唯一參數,可省略函數空括號:
   persions.maxBy{ persion:Persion -> persion.age }
省略lambda參數類型(上下文自動推斷類型)
persions.maxBy{ persion-> persion.age }   
使用默認參數名稱
persions.maxBy{ it.age }  //it 是自動默認生成的參數集合的函數式API
在kotlin中有很多跟集合操作相關的擴展函數,這種擴展函數無疑為我們減輕了很多負擔,這使得Kotlin相比java語法顯得更加簡單和高效的地方之一,kotlin中在合適地方使用這些標準庫函數可以幫助我們更加高效開發,同時使得我們代碼結構和邏輯顯得更加簡潔和清晰;
函數(得函數者得天下)
  • [函數修飾符] <fun>[函數名稱]([參數列表])[:返回值類型]{[函數體]}
  • [函數修飾符] <fun>[函數名稱]([參數列表])=[表達式]
*注:[]中的內容可省略,編譯器可進行類型推導得出
/** * 根據時間字符串返回日期 */private fun getDate(dateStr:String): Date {    val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")    return sdf.parse(dateStr)}/** * 傳入兩個整形數,計算他們的和并輸出 */fun add(num1:Int,num2:Int){    println("$num1 + $num2 = ${num1+num2}")}/** * 傳入姓名,輸出 Hi [傳入的姓名] */fun sayHi(name:String)=println("Hi $name")
  • 匿名函數
匿名函數就是沒有函數名稱的函數,但是匿名函數必須賦值給一個變量/常量
/** * 匿名函數 */val sayHi = fun(name:String)=println("Hi $name")filter
filter函數遍歷集合,并返回符合傳入lambda表達式為ture條件的集合元素,首先明白我們操作的是集合結構,并且返回的也是集合,filter函數幫助我們過濾出lambda表達式中符合條件的元素,舉例說明:
var list=listOf(1,2,3,4)prinltn (list.filter() { it % 2==0 })// [2,4]  只有偶數留下來
上面結果返回的是一個新集合,集合中只包含外匯返傭那邊符合lambda中判斷式的元素,即:filter函數選出了匹配給定判定式的元素;
val persions= listOf(Persion("zhangsan",30),Persion("wangwu",32),Persion("liuxing",21))println(persions.filter{it.age<30})// Persion("liuxing",21)map
filter函數不會改變這些元素的值,幫助我們從這些集合中篩選出符合條件的元素,如果需要對集合元素做修改或者變換需要用到map操作符;
map函數對集合中每個元素應用給定的函數并把結果放到一個新集合中;
var list=listOf(1,2,3,4)prinltn (list.map { it * it })// [1,4,9,16]  
同filter函數,返回的是一個新的集合,原集合數據并沒有修改或者破壞,并且新集合包含的元素個數不會變化,只是對集合中元素應用了給定的函數變換,即:map對集合中每個元素應用了lambda表達式;
val persions= listOf(Persion("zhangsan",30),Persion("wangwu",32),Persion("liuxing",21))println(persions.map{     it.name})// [zhangsan,wangwu,liuxing]
也可以使用成員引用寫法:
println(persions.map(Persion::name))all
all函數檢查集合中所有元素是否滿足給定判定式,返回值是Boolean類型的,例如:
val peoples=listOf(Persion("zhangsan",27),Persion("wangwu",22))println(peoples.all{it.age>25})// falseany
any函數檢查集合中是否存在某個元素符合給定判斷式,返回值也是Boolean類型,例如:
val peoples=listOf(Persion("zhangsan",27),Persion("wangwu",22))println(peoples.any{it.age>25})// true
注意:!all 加上條件等價于用any加上這個條件的取反來替換,反之亦然!
count
如果你想知道有多少個元素符合條件,可以使用count函數將結果返回,例如:
println(peoples{it.age>20})// 2 find
要找到第一個滿足給定判定式的元素,可以使用find函數,例如:
println(peoples.find{it.age>25})// [ "zhangshan", 27 ]with
“with” 函數用來對同一個對象執行多次操作,不需要反復引用對象名稱;
“with” 返回的值是執行lambda代碼的結果,該結果就是lambda中最后一行代碼的值;
apply
“apply” 函數用來對同一個對象執行多次操作,也不需要反復引用對象名稱;
“apply” 返回的值是元素本身(接受者本身);
類成員
  • 屬性:或者說成員變量,類范圍內的變量
  • 方法:或者說成員函數,類范圍內的函數
函數和方法的區別:
函數強調功能本身,不考慮從屬
方法的稱呼通常是從類的角度出發
只是叫法不同而已
  • 定義屬性
構造方法參數中val/var 修飾的都是屬性
類內部也可以定義屬性
class Hello(val aFiled:Int,notAField:Int){    var anotherField:Float = 3f}
  • 屬性訪問控制
屬性可以定義getter/setter
val a: Int=0    get()=field    var b: Float = 0f    get(){        return field / 3;    }    set(value){field = value}
  • 屬性初始化
屬性的初始化盡量在構造方法中完成
無法在構造方法中初始化,嘗試降級為局部變量
var 用 lateinit 延遲初始化,val 用 lazy 延遲初始化
可空類型謹慎用 null 直接初始化

分享到:  QQ好友和群 QQ空間 微信
收藏
收藏0
支持
支持0
反對
反對0
您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

領先的中文移動開發者社區
18620764416
7*24全天服務
意見反?。[email protected]

掃一掃關注我們

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粵ICP備15117877號 )