日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

读书笔记『Kotlin实战』

發布時間:2024/3/7 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 读书笔记『Kotlin实战』 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

P18:在Kotlin中沒有聲明數組類型的特殊語法,數組就是類

P19:在Kotlin中if是有結果的表達式

fun mac(a:Int,b:Int):Int{ return if(a>b) a else b}

P25:自定義訪問器

class Retangle(val height:Int, val width:Int) {val isSqual:Booleangen() { return height == width } }

P30:在"when"中使用任意對象

fun mix(cl:Color, c2:Color) {when(setOf(c1, c2)) {setOf(RED, YELLOW) -> ORANGEsetOf(YELLOW, BLUE) -> GREENsetOf(Blue, VIOLET) -> INDIGO} }

P37:迭代數字:區間和數列

  • 區間:for( i in 1 … 100 ) { print( i ) }
  • 步長區間:for( i in 100 downTo 1 step 2 )
  • 半閉合區間:for( x in 0 util size ),等同于for( x in 0 … size-1 )

P38:迭代map

  • for( letter.binary ) in list.withIndex() { “$index: $element”}

P41:Kotlin中throw結構是一個表達時刻,能作為另一個表達式的一部分使用:

val percentPage = if( num in 0..100) number else IllegalArgumentExcetion()

P49:在Kotlin中方法參數可以指定默認值

fun testDefaultArg(a:Int,b:Int = 11,c:Int=22) {println("$a,$b,$c") } >>>println("$a,$b,$c") //輸出:9,11,22

P51:頂層函數和頂層方法都會編譯成靜態成員,如果想要public static final,可以使用const修飾頂層屬性。

P53:擴展函數式一個類的成員函數,不過它定義在類的外面,擴展函數不能訪問私有或受保護的成員

fun String lastChar():char = this.get(this.lenght - 1)

P54:如果導入的函數存在重名,可以使用as來標識別名

import strings.lastChar as last

P57擴展函數不存在重寫,因為Kotlin會把它們當做靜態函數對待。另外成員函數的優先級高于擴展函數

P60:中綴調用:var map = mapOf(1 to “one”,2 to “two”);解構聲明:val(number,name) = 1 to “one”

P69:Kotlin中接口是可以包含屬性的。Kotlin中嵌套的類默認并不是內部類:它們并沒有包含對其他外部類的隱式引用。

P72:如果繼承有兩個相同的方法,需要使用"<>"顯式地指定實現哪一個

override fun showOff {super<Callable>.showOff()super<Focusable>.showOff() }

P73:Kotlin中的類默認是final,如果希望這個類能夠被繼承,需要使用open修飾符修飾。已經重寫了的方法,如果沒有final修飾,表明它是開放的。

P75:Kotlin中默認的可見性是public;Kotlin中一個外部類不能訪問嵌套類的private成員。

P77:在Java中,在一個類中聲明另一個類時,這個類默認是內部類,內部類持有外部類的引用。要去除這種引用,需要把內部類聲明成static的。在Kotlin中沒有顯式修飾符的嵌套類與Java中的static是一樣的,要把它變成內部類,需要使用inner修飾。

P79:密封類:用sealed修飾的類對可能創建的子類做出了嚴格的限制。所有直接子類必須嵌套在父類中。sealed修飾符隱含這個類是一個open類

P82:如果所有的構造方法參數都有默認值,編譯器會生成一個額外的不帶參數的構造方法來使用這些默認值

P85:在Kotlin中,接口可以包含抽象屬性聲明,者意味著實現User接口的類需要提供一個取得抽象屬性的方式。

interface User { val nickname:String} class PrivateUser(override val nickname:String):User

P88:在非空屬性上使用lateInit修飾符表明這個屬性會將初始化推遲到構造方法被調用后。

P90:如果想進行引用比較,可以使用**=運算符,這與Java中的**效果一樣。

P92:Kotlin中數據類(data class)會自動幫你生成通用方法,如:toString、equals、hashCode。另外還多生成了一個copy方法,用于修改val參數。

P93:當你需要向類中添加一些行為的時候,Kotlin中提供了類委托的支持,無論什么時候實現一個接口,都可以使用by關鍵字將接口的實現委托到另外一個對象。好處是不需要實現一堆接口中定義的方法,如:

class DelegatingCollection<T>(innerList:Collection<T> = ArrayList<T>()):Collection<T> by innerList{}

P95:Kotlin中object關鍵字的核心是:定義一個類并同事創建一個實例。對象聲明:定義單例的一種方式,對象聲明中可以包含屬性、方法、初始化語句塊等的聲明,但是不能包含構造方法,因為對象聲明在定義時就創建了對象,不需要構造方法;在Java中調用對象聲明使用INSTANCE來訪問靜態對象。

P98:伴生對象:可以持有工廠方法和其他與這個類相關,但在調用時并不依賴類實現的方法。它們的成員可以通過類名來訪問。

P103:對象表達式:用來替換Java的匿名內部類。和Java匿名內部類只能擴展一個類或實現一個接口不同,Kotlin的匿名對象可以實現多個接口或不實現接口。另外對象表達式中的代碼可以訪問創建它的函數中的變量,訪問并沒有被限制在final變量,可以在代碼中修改變量值。(對于非final變量來說,它的值被封裝在一個特殊的包裝器中,這樣你就可以改變這個值,而這個包裝器的引用會和lambda代碼一起存儲)

P108:Lambdab表達式的語法:{ x:Int,y:Int -> x + y },實例:people.maxBy ({p:Person -> p.age}) =(如果lambda是函數調用的最后一個實參,它可以放在括號外面)> people.maxBy (){p:Persion -> p.age} =(當lambda時唯一的實參,可以去掉括號)> people.maxBy{p:person -> p.age} =(和局部變量一樣,如果lambda參數的類型可以被推導出來,就可以省略)> people.maxBy{p -> p.age} =(如果當前上下文只有一個參數,且能被推導出類型,可以使用)> people.maxBy{ it.age }

P114:成員引用,提供了簡明語法,來創建一個調用的單個方法(普通函數,構造函數等)或者訪問單個屬性的函數值。使用雙冒號::來實現,如:

fun salute() = println("Salute!") >>> run(::salute) //引用頂級函數

P117:filter函數可以從集合中移除你不想要的元素,但它不會改變這些元素;map函數對集合中的每一個元素應用給定的函數并把結果收集到一個新集合中。

val list = listOf(1,2,3,4) >>> println(list.map{ it * it}) //輸出[1,4,9,16]

P118:Kotlin中,可以使用all、any、count、find、!all來檢查集合中的所有元素是否符合某個條件,如:

val canBeInClub27 = { it.age <= 27} //條件 val people = listOf(Person("A",27),Person("B",22)) >>>println(peole.all(canBeInClub27)) //輸出:false

P119:使用groupBy把元素按不同的特征劃分為不同的分組。如:

val p = listOf(Person("A",1),Person("B",1),Person("C",2)) >>>println(p.groupBy{ it.age }) //輸出{1=[Person(name=A, age=1), Person(name=B, age=1)], 2=[Person(name=C, age=2)]},有List轉換成了Map<Int,List<Person>>

P120flatMap根據實參給定的函數對集合中的每個元素做變換,然后把多個列表合并(或者說平鋪)成一個列表。而如果不需要做任何變換,只需要平鋪一個集合,可以使用flatter函數

P121Kotlin惰性集合操作的入口是Sequence接口,這個接口中只包含一個iterator方法,用來從序列中獲取值;Sequence的強大之處在于序列中的元素求值是惰性的,因此使用序列可以更高效的對集合元素執行鏈式操作,而不需要創建額外的集合來保存過程中產生的中間結果。

P123:序列操作:sequence.map{ … }.filter{ … }.toList(),其中map和filter是中間操作,是惰性的,toList()是末端操作,返回結果。所謂惰性就是,只有在請求結果時才會真的進行中間操作。另外,序列中時逐元素處理的,處理完一個元素的全部中間操作,才會進行下一個,意味著不會發生任何變換

P125:使用generateSequence函數給定序列中的前一個元素,這個函數會計算出下一個元素。

val naturalNumbers = generateSequence(0){ it + 1} val numbersTo100 = naturalNumbers.takeWhile{ it <= 100} >>>println(numbersTo100.sum()) //同樣的,numbersTo100也是惰性操作,只有調用sum()請求結果是才會進行計算

P130:注意lambda內部沒有匿名對象那樣的this:沒有辦法引用到lambda轉換成的匿名類實例。從編譯器的角度來看,lambda是一個代碼塊,而不是一個對象,而且也不能把它當成對象引用。Lambda中的this引用指向的是包圍它的類。

P131:帶接收者的lambda:在lambda函數體內可以調用一個不同對象的方法,而且無須借助任何額外限定符;如with函數:

fun alphabet():String{val _sb = StringBuilder()return with(_sb) { //實際上是一個接收兩個參數的函數,第一個函數時_sb,第二個函數時lambda,with函數把它的第一個參數轉換成第二個參數的接收者,可以使用this指代接收者,this也可以省略。for(letter in 'a' .. 'z') {this.append(letter) //this}this.toString()} }

P134:apply被聲明成一個擴展函數。它的接收者變成了作為實參的lambda的接收者。類似于Builder,如:

TextView(context).apply { text = "Sample Text"textSize = 20.0 }

P138:Kotlin中的可空類型特性是為了把運行的空指針異常轉變為編譯期的錯誤檢測。問號可以加在任何類型的后面來表示這個類型的變量可以存儲null引用

Type? = Type or null

可空標識符(?)最重要的操作是和null進行比較,一旦你進行了比較,編譯器會記住,并且再這次比較發生的作用域內把這個值當做非空對象類對待。

P141:安全調用符(?.),它允許你把一次null檢查和一次方法調用合并成一個操作。如:

s?.toUpperCase() => if(s != null) s.toUpperCase() else null

P143Elvis(?:)運算符接收兩個運算數,如果第一個運算數不為null,運算結果就是第一個運算數;如果第一個運算數為null,結果就是第二個運算數。如:

fun strLenSafe(s:String?):Int = s ?. length ?: 0 >>>println(strLenSafe(null)) //輸出:0 //結合Exception val address = person.company?.address ?: throw IllegalArgumentException("No address")

P145:安全轉換:**as?**經常Elvis運算符結合使用,如:

val otherPerson = o as? Person?: return false

P146:非空斷言(!!),可以將任何值轉換成非空類型。如果對null值做非空斷言,則會拋出異常。明確告訴編譯器知道可能為空,也愿意接受異常。

P148let函數可以把一個調用它的對象變成lambda表達式的參數。如:

if(email!= null) sendEmailTo(email) -> email?.let{ email -> sendEmailTo(email)}

P149:Kotlin通常要求你在構造方法中初始化所有屬性,如果某個屬性是非空類型,你就必須提供非空的初始化值。如果你使用可空類型,意味著該屬性的每一次訪問都需要null檢查或者**!!**運算符;延遲初始化標識符(lateinit)只能修飾var,因為val是final的,在編譯期就確定了其變量值,也不存在延遲初始化的需求。

P153:**Kotlin中所有泛型類和泛型函數的類型參數默認都是可空的。**要是類型參數非空,必須要為它指定一個非空的上界,如:

fun <T:Any> printHashCode(t:T) {println(t.hashCode()) }

P154Kolin把那些定義在Java代碼中的類型看成平臺類型,當調用java中的方法時處理參數,或者重寫java接口時處理參數。參數可以是可空也可以是非空的,需要小心處理。

P160:Kotlin不會自動地把數字從一種類型轉換成另外一種,即使是轉換成范圍更大的數據類型。每種接觸類型都有轉換函數,如:toInt(),toLong(),toShort()等。equals除了會比較兩個元素中存儲的值,還會比較裝箱類型

P165:List<Int?> 表示列表中的元素可空,List? 表示整個列表可空,但是其中的元素不可空。

P167:Kotlin的集合設計和Java有所不同,它把訪問集合數據的接口(kotlin.collections.Collection)和修改集合數據的接口(kotlin.collections.MutableCollection,繼承了Collection接口)

P168只讀集合不一定是不可變的,當一個變量同時被只讀集合和可變集合引用時,他就可能被改變。

P173Kotlin中的數組是一個帶有類型參數的類,創建數組的方式有包含:arrayOf、arrayOfNulls、以及Array構造方法接收數組大小和一個lambda表達式,調用lambda表達式來創建每一個數組元素。如:

val letters = Array<String>(26) {i -> ('a' + i).toString() }

P174:使用toTypedArray可以將集合中的元素按照元素類型轉換成對應的數組;Kotlin中數組類型包含的類型參數始終會變成對象類型,想要在數組中包含基礎類型,需要使用特殊的數組類,如IntArray、BooleanArray等。

P180:重載算數運算符,不能定義自己的運算符。Kolin限定了你能重載哪些運算符,以及你需要在你的類中定義的對應名字的函數(如:plus、minus、times、div、mod)。具體如下:

data class Point(val x:Int,val y:Int) {operator fun plus(other:Point):Point {return Point(x + other.x,y + other.y)} } >>> println(Point(2,4) + Point(3,6)) //輸出:Point(x=5,y=10)

P189:在Kotlin中,下標運算符是一個約定。使用下標運算符讀取元素會被轉換為get運算符方法的調用,并且寫入元素將調用set。如下,其實是個擴展函數

operator fun Point.get(index:Int):Int {return when(index) {0 -> x1 -> yelse -> throw IndexOutOfBoundsException("Invaild coordinate $index")} } >>>println(Point(11,22)[0]) //輸出:11

P195屬性委托,可以把一個值的讀取委托給別的輔助對象,會為輔助對象生成get、set方法,當讀取屬性值的時候調用get方法。屬性委托的一種常見用法是懶加載:

class Person(val name:String) {val emails by lazy {loadEmails(this)} }

P207高階函數就是以另一個函數作為參數或者返回值的函數。在Kotlin中,函數可以用lambda或者函數引用來表示。高階函數語法:(參數類型列表) -> 返回值類型,需要注意的是,一個函數類型聲明總是需要一個顯式的返回類型,在這種場景下Unit是不能省略的。如下:

(int,String) -> Unit

高階函數作為參數使用一:

fun twoAndThree(operation:(Int,Int) -> Int) {val result = operation(2,3)println("The result is $result") } >>>twoAndThree({a,b -> a * b}) //輸出:The result is 6 >>>twoAndThree({a,b -> a + b}) //輸出:The result is 5

高階函數作為參數使用二:

fun String.filter(predicate:(Char) -> Boolean):String {var sb = StringBuilder()for(index in 0 until length) {val element = get(index)if(predicate(element)) sb.append(element)}return sb.toString() } >>>println("ab1c".filter { it in 'a' .. 'z' }) //輸出:abc

P211:一個函數類型的變量時FunctionN接口的一個實現,Kotlin標準庫定義了一系列的接口,Function0,Function1<P1,R),Function<P1,P2,R>等。每個接口定義了一個invoke方法,調用這個方法就會執行函數。

P214:返回函數的函數,really cool!,聲明一個返回另一個函數的函數,需要指定一個函數類型作為返回類型

enum class Delivery {STANDARD,EXPEDITED} class Order(val itemCount:Int) fun getShippingCostCalculator(delivery: Delivery):(Order) -> Double {if(delivery == Delivery.EXPEDITED) {return { order -> 6 + 2.1 * order.itemCount}}return { order -> 1.2 * order.itemCount} }

P218:lambda表達式會被正常的編譯成匿名類,這表明沒調用一次lambda表達式,一個額外的類就會被創建。并且如果lambda捕捉了某個變量,那么每次調用的時候都會創建一個新的對象。這會帶來運行時的額外開銷,導致使用lambda比使用一個直接執行的相同代碼的函數效率更低。當一個函數被聲明為inline時,它的函數體是內聯的,換句話說,函數體會直接替換到函數被調用的地方,而不是被正常調用。

P221:如果lambda作為參數被調用,這樣的代碼能被容易的內聯,如果lambda在某個地方被保存起來,此時lambda表達式將不能被內聯,因為必須要有一個包含這些代碼的對象存在

P226:只有在以lambda作為參數的函數是內聯函數的時候才能從更外層的函數返回(return)。一個非內聯函數可以把它的lambda保存在變量中,可能在函數返回后繼續使用。可以使用標簽,從局部返回:

fun lookForAlice2(boys:List<Boy>) {boys.forEach aa@{if(it.name == "Alice") {println("Found!")return@aa}}println("Alice is not found") } >>>forEach是一個Kotlin自帶的內聯函數,這里使用標簽從局部返回,不會執行println語句代碼

229return從最近使用fun關鍵字聲明的函數返回,在匿名函數中,不帶標簽的return會從匿名函數返回,而不是從包含匿名函數的函數返回。

P236:和Java中使用關鍵字extends來約束泛型形參上界不同,Kotlin中使用**?*來約束上界,如下:

fun <T : Number> List<T>.sum() : T

一旦指定了類型形參T的上界,你就可以調用定義在上界類中的方法。如:

fun <T:Number> oneHalf(value:T):Double {return value.toDouble() / 2.0 }

P237:默認的泛型參數的上界是Any,如果想限定實參為非空的,可以指定T : Any;可以為一個類型參數指定多個約束,如下:

fun <T> ensureTrailingPeriod(seq:T):T where T:CharSequence,T:Appendable {if(!seq.endsWith('.')) {seq.append('.')}return seq } >>>println(ensureTrailingPeriod(StringBuilder("ABC"))) //輸出:ABC.

P239:泛型的類型擦除,泛型之所以能限制容器或者方法實參的類型,是因為在編譯期做了校驗,但是到了運行是泛型類型會被擦出掉,也就是編譯期不會區分List<String>和List<Student>;不能判斷一個對象是否是List<String>,只能使用List<?>判斷該對象是否是List;在Kotlin中使用星號投影 :

if(value is List<*>){ ... }

P241:Kotlin中內聯函數的類型形參能夠被實化,意味著可以在運行時引用實際的類型實參。把函數聲明成inline并且用relified標記類型參數:

inline fun <reified T> isA(value:Any) = value is T >>>println(isA<String>("abc")) //輸出:true

注意,帶relified類型參數的inline函數不能在java代碼中調用。

P244:使用實化類型參數代替類引用(class),如Activity中的startActivity函數:

inline fun<relified T:Activity> Context.startActivity() {val intent = Intent(this,T::class.java)startActivity(intent) } >>>startActivity<DetailActivity>()

P246:變型描述擁有相同基礎類型和不同類型實參的類型之間是如何關聯的(如List和List);當一個可變字符串列表(MutableList)傳遞給一個期望Any對象列表的函數是否安全,取決于該字符串列表中的元素是否可變,如果是可變的,意味著列表中的元素類型可能不一致,則此時它是不安全的,編譯器會禁止編譯通過。

P248:協變:保留子類型化關系。如果Cat是Animal的子類型,那么如果List也是List的子類型,我們說子類型化被保留了;類型參數T上用關鍵字out修飾有兩層含義

  • 子類型化會被保留(Producer是Producer的子類型)
  • T只能用在out位置
  • interface Transformer<T>{fun transform(t:T):T //前面的T稱為"in"位置,只能消費類型為T的值;后面的T稱為"out"位置,只能生產類型為T的值 }

    需要注意,位置規則只覆蓋了類外部可見的(public、protected和internal)API。私有方法的參數既不在in位置也不在out位置。in和out有點類似于java中的<? extend T>和<? super T>指定類型的上、下界限。

    P253

    P256:可以為類型參數指定in、out來限制其為消費(可寫)、生產(只讀)。

    P257:星號投射類似于java中的MyType<?>,你不知道里面存的是什么類型,所以不能往里存數據,但是你可以往外取東西,因為里面的元素總是Any?的子類型。

    P264:Kotlin中注解指定實參的語法和Java有所不同

  • 要把一個類指定為注解實參,在類名后面加上**::class**,如:@MyAnnotation(MyClass**::class**)
  • 要把另一個注解指定為一個實參,去掉該注解名稱前面的@,如@Deprecated(“Use removeAt(index) instead.”, ReplaceWith(“removeAt(index)”)),其中ReplaceWith也是一個注解。
  • 要把一個數組指定為一個實參,使用arrayOf函數,如:@RequestMapping(path=arrayOf(“A”,“B”))
  • 要把屬性當做注解的實參使用,需要使用const修飾符修飾。
  • P274:在Kotlin中使用反射,有兩種反射API,一種是標準的Java反射,定義在java.lang.reflect;第二種是Kotlin反射API,定義在kotlin.reflect中,Kotlin反射API被打包成獨立的jar文件,kotlin-reflect.jar,需要自己添加依賴導入進來。在Kotlin中使用反射需要先使用javaClass獲取它的Java類,然后再通過.kotlin擴展屬性,完成從Java到Kotlin的過渡。

    val child = Child("Lucy") val kClass = child.javaClass.kotlin println(kClass.simpleName) //輸出:Child kClass.memberProperties.forEach{ println(it.name) } //輸出:name

    P293:Kotlin的DSL(領域特定語言,專注在特定任務或領域上,并放棄與該領域無關的功能,如SQL)是完全靜態類型的,就像語言的其他功能一樣。這意味著靜態類型的所有優勢,比如編譯時錯誤的檢測,以及更好的IDE支持,在你的API上使用DSL模式時仍然有效。

    299:帶接收者的lambda是Kotlin的一個強大特性,它可以讓你使用一個結構來構建API,擁有結構是區分DSL和普通API的關鍵特征。帶接收者的lambda格式:

    String.(Int, Int) -> Unit;String為接收者類型,(Int, Int)為參數類型

    fun buildString(builderAction:StringBuilder.()-> Unit):String {val sb = StringBuilder()sb.builderAction()return sb.toString() } val s2 = buildString {this.append("Hello")append("World") }

    當你將一個普通函數類型轉換為擴展函數類型時,其調用方式也發生了變化。想調用一個擴展函數那樣調用lambda,而不是將對象作為參數傳遞給lambda。

    val appendExcl :StringBuilder.() -> Unit = {this.append("!")} val s3 = StringBuilder("Hi") s3.appendExcl() println(s3) //輸出:Hi!

    可以看到這里的帶接收者的Lambda表達式,有點像一個匿名的擴展函數,且該匿名擴展函數的對象時調用者自己

    P310invoke約定允許把自定義類型的對象當做函數一樣調用。你已經見過函數類型的對象,它們可以作為函數調用;使用invoke約定,也可以定義支持同樣語法的對象。get是我討論過的約定之一,它允許你使用下標運算符來訪問一個對象。

    class G(val g:String) {operator fun invoke(name:String) {println("$g,$name!")} } G("x")("w") //輸出:x,w!

    P311:Lambda除非是內聯的,都是被編譯成實現了函數式接口(Function1等)的類,而這些接口定義了具有對應數量參數的invoke方法。

    P312:將lambda轉換成一個實現了函數類型接口的類,并重寫接口的invoke方法;是進行重構的一種方式。這種方法的優點是從lambda函數體重抽取的方法的作用域被金可能縮小了。

    data class Dog(val name:String,val color:String,val height:Int)class GoodDogPredicate():(Dog) -> Boolean {override fun invoke(dog: Dog): Boolean {return dog.isGoodColor() && dog.isGoodHeight()}private fun Dog.isGoodColor():Boolean {return color == "White"}private fun Dog.isGoodHeight():Boolean {return height < 50} }val dog1 = Dog("Tom","Yellow",40) val dog2 = Dog("Yame","White",40) val dog3 = Dog("Petty","White",100) val predicate = GoodDogPredicate() for(d in listOf(dog1,dog2,dog3).filter(predicate)) {println(d.name + " is a good dog!") //Yame is a good dog }

    總結

    以上是生活随笔為你收集整理的读书笔记『Kotlin实战』的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。