kotlin是 JetBrains 在 2010 年推出的基于 JVM 的新編程語言。開發(fā)者稱北发,設(shè)計它的目的是避免 Java 語言編程中的一些難題。比如:在 Kotlin 中類型系統(tǒng)控制了空指針引用脊框,可以有效避免 Java 中常見的NullPointException。
作為一個跨平臺的語言,Kotlin 可以工作于任何 Java 的工作環(huán)境:服務(wù)器端的應(yīng)用昂利,移動應(yīng)用(Android版)祥国,桌面應(yīng)用程序。
Kotlin的優(yōu)勢
相比于 Java碳抄,Kotlin 有著更好的語法結(jié)構(gòu)愉老,安全性和開發(fā)工具支持。Kotlin 中沒有基礎(chǔ)類型剖效,數(shù)組是定長的嫉入,泛型是安全的,即便運(yùn)行時也是安全的璧尸。此外咒林,該語言支持閉包,還可通過內(nèi)聯(lián)進(jìn)行優(yōu)化爷光。不過垫竞,它不支持檢查異常(Checked Exceptions),許多語言設(shè)計者認(rèn)為這是它的瑕疵蛀序。不論如何欢瞪,重要的是 Java 和 Kotlin 之間的互操作性:Kotlin 可以調(diào)用 Java,反之亦可徐裸。
變量
fun main(args: Array<String>) {
var quantity = 5
val price: Double = 20.3
val name: String = "大米"
println("單價:$price")
println("數(shù)量:$quantity")
println("產(chǎn)品:$name 總計:${quantity * price}")
}
in關(guān)鍵字的使用
//如果存在于區(qū)間(1,Y-1)遣鼓,則打印OK
if (x in 1..y-1)
print("OK")
//如果x不存在于array中,則輸出Out
if (x !in 0..array.lastIndex)
print("Out")
//打印1到5
for (x in 1..5)
print(x)
//遍歷集合(類似于Java中的for(String name : names))
for (name in names)
println(name)
//如果names集合中包含text對象則打印yes
if (text in names)
print("yes")
when表達(dá)式
類似于 Java 中的 switch重贺,但是 Kotlin 更加智能骑祟,可以自動判斷參數(shù)的類型并轉(zhuǎn)換為響應(yīng)的匹配值。
fun cases(obj: Any) {
when (obj) {
1 -> print("第一項(xiàng)")
"hello" -> print("這個是字符串hello")
is Long -> print("這是一個Long類型數(shù)據(jù)")
!is String -> print("這不是String類型的數(shù)據(jù)")
else -> print("else類似于Java中的default")
}
}
智能類型推測
判斷一個對象是否為一個類的實(shí)例气笙,可以使用is關(guān)鍵字
與 Java 中的instanceof關(guān)鍵字類似次企,但在 Kotlin 中如果已經(jīng)確定了一個對象的類型,可以在接下來的代碼塊中直接作為這個確定類型使用健民。
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// 做過類型判斷以后抒巢,obj會被系統(tǒng)自動轉(zhuǎn)換為String類型
return obj.length
}
//同時還可以使用!is,來取反
if (obj !is String){
}
// 代碼塊外部的obj仍然是Any類型的引用
return null
}
空值檢測
Kotlin 是空指針安全的秉犹,也就意味著你不會再看到那惱人的空指針異常蛉谜。
例如這句代碼 println(files?.size)稚晚,只會在files不為空時執(zhí)行。
以及型诚,你可以這樣寫
//當(dāng)data不為空的時候客燕,執(zhí)行語句塊
data?.let{
//...
}
//相反的,以下代碼當(dāng)data為空時才會執(zhí)行
data?:let{
//...
}
函數(shù)
函數(shù)的聲明
函數(shù)使用關(guān)鍵字fun聲明狰贯,如下代碼創(chuàng)建了一個名為say()的函數(shù)也搓,它接受一個String類型的參數(shù),并返回一個String類型的值
fun say(str: String): String {
return str
}
同時涵紊,在 Kotlin 中傍妒,如果像這種簡單的函數(shù),可以簡寫為
fun say(str: String): String = str
如果是返回Int類型摸柄,那么你甚至連返回類型都可以不寫
fun getIntValue(value: Int) = value
函數(shù)的默認(rèn)參數(shù)
你也可以使用默認(rèn)參數(shù)來實(shí)現(xiàn)重載類似的功能
fun say(str: String = "hello"): String = str
這時候你可以調(diào)用say()颤练,來得到默認(rèn)的字符串 "hello",也可以自己傳入?yún)?shù)say("world")來得到傳入?yún)?shù)值驱负。
有時參數(shù)非常多的時候嗦玖,也可以使用多行參數(shù)的寫法,它們是相同的
fun say(firstName: String = "Tao",
lastName: String = "Zhang"){
}
變參函數(shù)
同 Java 的變長參數(shù)一樣跃脊,Kotlin 也支持變長參數(shù)
//在Java中宇挫,我們這么表示一個變長函數(shù)
public boolean hasEmpty(String... strArray){
for (String str : strArray){
if ("".equals(str) || str == null)
return true;
}
return false;
}
//在Kotlin中,使用關(guān)鍵字vararg來表示
fun hasEmpty(vararg strArray: String?): Boolean{
for (str in strArray){
if ("".equals(str) || str == null)
return true
}
return false
}
擴(kuò)展函數(shù)
你可以給父類添加一個方法酪术,這個方法將可以在所有子類中使用器瘪。例如,在 Android 開發(fā)中绘雁,我們常常使用這樣的擴(kuò)展函數(shù):
fun Activity.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, message, duration).show()
}
將函數(shù)作為參數(shù)
Kotlin 中娱局,可以將一個函數(shù)作為參數(shù)傳遞給另一個函數(shù)
fun invokeModule(webview: View?, cmd: String, parameters: String,
callback: String,
callbackFunction: (String, String) -> Unit):String?
上面的代碼中,我們傳入了一個(String, String) -> Unit的參數(shù)
kotlin類特性
與 Java 相同咧七,Kotlin 聲明類的關(guān)鍵字是class。類聲明由類名任斋、類頭和類體構(gòu)成继阻。
其中類頭和類體都是可選的; 如果一個類沒有類體,那么花括號也是可以省略的废酷。
構(gòu)造函數(shù)
Kotlin 的構(gòu)造函數(shù)可以寫在類頭中瘟檩,跟在類名后面,如果有注解還需要加上關(guān)鍵字constructor澈蟆。這種寫法聲明的構(gòu)造函數(shù)墨辛,我們稱之為主構(gòu)造函數(shù)。例如下面我們?yōu)镻erson創(chuàng)建帶一個String類型參數(shù)的構(gòu)造函數(shù)趴俘。
class Person(private val name: String) {
fun sayHello() {
println("hello $name")
}
}
在主構(gòu)造函數(shù)中不能有任何代碼實(shí)現(xiàn)睹簇,如果有額外的代碼需要在構(gòu)造方法中執(zhí)行奏赘,你需要放到init代碼塊中執(zhí)行。
class Person(private var name: String) {
init {
name = "Zhang Tao"
}
internal fun sayHello() {
println("hello $name")
}
}
protected 在 “top-level” 中不可以使用太惠,即不能修飾包級別的方法或者屬性等
private 聲明在包含聲明的源文件中可見
internal 聲明磨淌,在同一模塊中的任何地方可見
次構(gòu)造函數(shù)
class Person(private var name: String) {
private var description: String? = null
init {
name = "Zhang Tao"
}
constructor(name: String, description: String) : this(name) {
this.description = description
}
internal fun sayHello() {
println("hello $name")
}
}
枚舉類
enum class Programer {
JAVA, KOTLIN, C, CPP, ANDROID;
}
密封類
sealed class BaseClass {
class Test1 : BaseClass() {
override fun test() {
println("Test1實(shí)例")
}
}
class Test2 : BaseClass() {
override fun test() {
println("Test2實(shí)例")
}
}
object Test3 : BaseClass() {
override fun test() {
println("Test3實(shí)例")
}
}
open fun test() {
println("BaseClass實(shí)例")
}
}
sealed 修飾的類稱為密封類,用來表示受限的類層次結(jié)構(gòu)凿渊。例如當(dāng)一個值為有限集中的 類型梁只、而不能有任何其他類型時。在某種意義上,他們是枚舉類的擴(kuò)展:枚舉類型的值集合也是受限的埃脏,但每個枚舉常量只存在一個實(shí)例,而密封類的一個子類可以有可包含狀態(tài)的多個實(shí)例搪锣。
data 數(shù)據(jù)類
data 修飾的類稱之為數(shù)據(jù)類。它通常用在我們寫的一些 POJO 類上彩掐。當(dāng) data 修飾后构舟,會自動將所有成員用operator聲明,即為這些成員生成類似 Java 的 getter/setter 方法佩谷。
編譯器自動從主構(gòu)造器中的屬性導(dǎo)入下面這些成員函數(shù):
- equals()/hashCode()
- toString()(形式為User(name=John,age=42))
- componentN()函數(shù)對應(yīng)著聲明的屬性順序
- copy()函數(shù)
data class User(val name: String, val age: Int)
伴生對象
由于 Kotlin 沒有靜態(tài)方法旁壮。在大多數(shù)情況下,官方建議是簡單地使用 包級 函數(shù)谐檀。如果你需要寫一個可以無需用一個類的實(shí)例來調(diào)用抡谐、但需要訪問類內(nèi)部的函數(shù)(例如,工廠方法或單利),你可以把它寫成一個用 companion修飾的對象內(nèi)的方法。我們稱companion修飾的對象為伴生對象桐猬。
class StringUtils {
companion object {
fun isEmpty(str: String): Boolean {
return "" == str
}
}
}
單例類的設(shè)計
class Single private constructor() {
companion object {
fun get():Single{
return Holder.instance
}
}
private object Holder {
val instance = Single()
}
}
通過關(guān)鍵字object
object Single{
}
委托
Kotlin 直接支持委托模式麦撵,更加優(yōu)雅,簡潔溃肪。Kotlin 通過關(guān)鍵字 by 實(shí)現(xiàn)委托免胃。有點(diǎn)像java的動態(tài)代理。
interface Animal{
fun bark()
}
class Dog :Animal {
override fun bark() {
println("Wang Wang")
}
}
class Cat(animal: Animal) : Animal by animal {
}
fun main(args: Array<String>) {
Cat(Dog()).bark()
}
這樣惫撰,我們就很成功的讓一只貓的叫聲用狗去代理掉了羔沙,于是上面的main方法執(zhí)行完后就變成了 Wang Wang。
屬性的委托
import kotlin.reflect.KProperty
// 定義包含屬性委托的類
class Example {
var p: String by Delegate()
}
// 委托的類
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, 這里委托了 ${property.name} 屬性"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$thisRef 的 ${property.name} 屬性賦值為 $value")
}
}
fun main(args: Array<String>) {
val e = Example()
println(e.p) // 訪問該屬性厨钻,調(diào)用 getValue() 函數(shù)
e.p = "Runoob" // 調(diào)用 setValue() 函數(shù)
println(e.p)
}
輸出結(jié)果:
Example@433c675d, 這里委托了 p 屬性
Example@433c675d 的 p 屬性賦值為 Runoob
Example@433c675d, 這里委托了 p 屬性
可觀察屬性 Observable
@[Kotlin 的標(biāo)準(zhǔn)庫中已經(jīng)內(nèi)置了很多工廠方法來實(shí)現(xiàn)屬性的委托扼雏。]
import kotlin.properties.Delegates
class User {
var name: String by Delegates.observable("初始值") {
prop, old, new ->
println("舊值:$old -> 新值:$new")
}
}
fun main(args: Array<String>) {
val user = User()
user.name = "第一次賦值"
user.name = "第二次賦值"
}
執(zhí)行輸出結(jié)果:
舊值:初始值 -> 新值:第一次賦值
舊值:第一次賦值 -> 新值:第二次賦值
閉包
一段程序代碼通常由常量、變量和表達(dá)式組成夯膀,然后使用一對花括號“{}”來表示閉合诗充,并包裹著這些代碼,由這對花括號包裹著的代碼塊就是一個閉包诱建。其實(shí)在簽名我們也介紹了全局和嵌套函數(shù)就是一種特殊的閉包蝴蜓。這里,我們總結(jié)了一下,Kotlin語言中有三種閉包形式:全局函數(shù)茎匠、自嵌套函數(shù)格仲、匿名函數(shù)體。
fun main(args: Array<String>) {
// 執(zhí)行test閉包的內(nèi)容
test
}
// 定義一個比較測試閉包
val test = if (5 > 3) {
println("yes")
} else {
println("no")
}
閉包的用途汽抚?
/**
* 計數(shù)統(tǒng)計
*/
fun justCount():() -> Unit{
var count = 0
return {
println(count++)
}
}
fun main(args: Array<String>) {
val count = justCount()
count() // 輸出結(jié)果:0
count() // 輸出結(jié)果:1
count() // 輸出結(jié)果:2
}
自執(zhí)行閉包
自執(zhí)行閉包就是在定義閉包的同時直接執(zhí)行閉包抓狭,一般用于初始化上下文環(huán)境。 例如:
{ x: Int, y: Int ->
println("${x + y}")
}(1, 3)
Lambda表達(dá)式
val printMsg = { msg: String ->
println(msg)
}
fun main(args: Array<String>) {
printMsg.invoke("hello")
}
帶接收者的with,apply
var s=with("abc"){
this.plus("d")
}
println(s)
apply始終返回座位實(shí)參傳遞給它的對象
var r="abc".apply {
this.plus("d")
}
println(r)
let表達(dá)式一般結(jié)合類型安全檢查使用
var x: String? = null
x?.let {
println("x=${it}")
}
集合和泛型
所有類聲明的泛型尖括號里面如果加入了 out 關(guān)鍵字造烁,則說明這個類的對象是只讀的否过,例如他只有:get()、size()等方法惭蟋,而沒有 set()苗桂、remove()等方法。
相反的告组,如果沒有加 out 關(guān)鍵字煤伟,或者換一種記法:如果開頭是 MutableXXX 那就是一個跟 Java 中用法一致的集合類。
open class A
open class B : A()
open class C : B()
class TypeArray<in A> {
//in 修飾了 A木缝,表示 A 是可以作為參數(shù)的便锨。
fun getValue(a: A): Int? {
return a?.hashCode()
}
//這段代碼是非法的,因?yàn)锳 不能被返回
fun getA(a: A): A? {
return a
}
}
集合的初始化
在 Kotlin 中我碟,集合類一般不使用構(gòu)造方法去初始化放案,而是使用同一的入口方法,例如初始化一個 MutableList矫俺,我們使用的是如下代碼:
val mutableList = mutableListOf(0, 1, 2, 3)
類似的初始化集合對象的方法還有
//創(chuàng)建一個 List<> 對象
var list = listOf(0, 1, 2)
//創(chuàng)建一個 Set<> 對象
val ss = setOf(1, 2, 4)
操作符
比如說輸出wifi密碼duowan123
java實(shí)現(xiàn):
final String[] a = new String[]{"a", "1", "u", "2", "o", "n", "3", "d", "w"};
final Integer[] indexs = new Integer[]{7, 10, 2, 4, 11, 8, 0, 5, 1, 3, 15, 6};
常用操作符
Kotlin 的操作符跟 RxJava 基本一致吱殉,不需要額外記憶。
下標(biāo)操作類
- contains —— 判斷是否有指定元素
- elementAt —— 返回對應(yīng)的元素厘托,越界會拋- IndexOutOfBoundsException
- firstOrNull —— 返回符合條件的第一個元素友雳,沒有 返回null
- lastOrNull —— 返回符合條件的最后一個元素,沒有 返回null
- indexOf —— 返回指定元素的下標(biāo)铅匹,沒有 返回-1
- singleOrNull —— 返回符合條件的單個元素押赊,如有沒有符合或超過一個,返回null
判斷類
- any —— 判斷集合中 是否有滿足條件 的元素
- all —— 判斷集合中的元素 是否都滿足條件
- none —— 判斷集合中是否 都不滿足條件包斑,是則返回true
- count —— 查詢集合中 滿足條件 的 元素個數(shù)
- reduce —— 從 第一項(xiàng)到最后一項(xiàng)進(jìn)行累計
過濾類
- filter —— 過濾 掉所有 滿足條件 的元素
- filterNot —— 過濾所有不滿足條件的元素
- filterNotNull —— 過濾NULL
- take —— 返回前 n 個元素
轉(zhuǎn)換類
- map —— 轉(zhuǎn)換成另一個集合(與上面我們實(shí)現(xiàn)的 convert 方法作用一樣);
- mapIndexed —— 除了轉(zhuǎn)換成另一個集合考杉,還可以拿到Index(下標(biāo));
- mapNotNull —— 執(zhí)行轉(zhuǎn)換前過濾掉 為 NULL 的元素
- flatMap —— 自定義邏輯合并兩個集合;
- groupBy —— 按照某個條件分組舰始,返回Map;
排序類
- reversed —— 反序
- sorted —— 升序
- sortedBy —— 自定義排序
- sortedDescending —— 降序
用于 Android 開發(fā)的工具
Kotlin 團(tuán)隊(duì)為 Android 開發(fā)提供了一套超越標(biāo)準(zhǔn)語言功能的工具:
- Kotlin Android 擴(kuò)展是一個編譯器擴(kuò)展咽袜, 可以讓你擺脫代碼中的 findViewById() 調(diào)用丸卷,并將其替換為合成的編譯器生成的屬性。
- Anko 是一個提供圍繞 Android API 的 Kotlin 友好的包裝器的庫 询刹,以及一個可以用 Kotlin 代碼替換布局 .xml 文件的 DSL谜嫉。
- Android KTX 一個 Kotlin 代碼的擴(kuò)展庫萎坷,比較常用的一些代碼塊,進(jìn)行封裝沐兰,然后在這個基礎(chǔ)上哆档,提供更良好的 API,供開發(fā)者使用住闯。
參考鏈接