對(duì)Kotlin的一次小調(diào)研
本文主要內(nèi)容
1,Kotlin簡單介紹一下
2,Android Developer意見了解一下
3,Android Stuido Kotlin Plugins環(huán)境搭建及配置
4,Kotlin常見語法糖(這個(gè)糖有點(diǎn)兒甜)
5,Kotlin與Java的相互調(diào)用
1,什么是Kotlin
Kotlin 是一個(gè)基于 JVM 的新的編程語言,由 JetBrains 開發(fā)罕扎。
Kotlin可以編譯成Java字節(jié)碼秃流,也可以編譯成JavaScript稚新,方便在沒有JVM的設(shè)備上運(yùn)行碉纳。
JetBrains镇草,作為目前廣受歡迎的Java IDE IntelliJ 的提供商乘凸,在 Apache 許可下已經(jīng)開源其Kotlin 編程語言橘券。
Kotlin已正式成為Android官方支持開發(fā)語言茉稠。
(節(jié)選自百度百科)
2,Android Developer關(guān)于Kotlin的看法
此前,我在"開源中國"上看到過一篇關(guān)于國外Developer對(duì)于Kotlin的看法的文章,感覺里面很多大神分析的挺有道理的,雖然是基于Kotlin早起的版本,但是其中的一些觀點(diǎn)挺值得我們?nèi)チ私庖幌?
17 位谷歌 Android 開發(fā)專家是如何看待 Kotlin 的描馅?
(不知道為什么link的鏈接被簡書添加了 link.jianshu.com導(dǎo)致無法跳轉(zhuǎn),地址如下:
https://www.oschina.net/news/85468/what-do-17-google-developers-experts-for-kotlin)
但是,我們是在國內(nèi),更多的時(shí)候要考慮國內(nèi)Developer的一些看法,對(duì)此,我請(qǐng)教了技術(shù)群中的一些朋友,他們其中有的人正在用,有的人正在考慮用,有的人在觀望,以下,是他們的一些看法,考慮到隱私相關(guān),涉及到公司名稱部分的已經(jīng)隱去,排名不分先后
深圳市Android開發(fā)工程師-Arthas·李(謹(jǐn)慎觀望):
我覺得吧,相比Java而言,代碼更簡潔,清晰,會(huì)有一陣子的新鮮,但是實(shí)際上.只是非常少一部分人會(huì)用吧。?也許再過個(gè)一年半載,熱度就下去了,具體要看谷歌爸爸給不給力推而线。
廣州市Android開發(fā)工程師-Terenas Menethil 顏(看好):
Kotlin能簡化大量的無用代碼铭污,有效的避免的空指針恋日。
代碼可讀性高,方便了團(tuán)隊(duì)成員維護(hù)嘹狞,降低了成本岂膳。
計(jì)劃在下個(gè)項(xiàng)目中引用,但是還是要看實(shí)際情況(人員,三方庫支持)。
上海市Android開發(fā)工程師-flyinbed(在用)
Kotlin具有現(xiàn)代化靜態(tài)編程語言的很多特點(diǎn)磅网,并大大的減少了重復(fù)代碼谈截,提高了編程效率,讓代碼邏輯更加清晰涧偷。
我就覺得 Java 這樣“冗長”的語言應(yīng)該慢慢退出歷史舞臺(tái)了簸喂,本來幾行代碼就能寫出了邏輯,換成java可以寫出20多行左右燎潮。
歷史的巨輪滾滾向前喻鳄,終究我們編碼會(huì)是越來越簡潔,工作量越來越少确封。
3 AS Kotlin Plusgins配置
(基于AS 3.0+)
①新建項(xiàng)目:
直接選中include Kotlin support即可
一路Next->Finish之后,就可以看到新建的MainActivity已經(jīng)是.kt格式了
②已有Java項(xiàng)目的轉(zhuǎn)換
直接在Tools菜單中config
選中對(duì)應(yīng)的module或All modules
IDE會(huì)自動(dòng)生成對(duì)應(yīng)的code(module中的.gradlew也會(huì)自動(dòng)配置)
更簡單的做法
直接在java code下創(chuàng)建一個(gè).kt文件,AS會(huì)提示需要configure,之后的流程就跟之前一樣
③java文件轉(zhuǎn)換成kotlin文件
AS中,自帶了可以轉(zhuǎn)換.java文件到.kt文件的插件,部分Java代碼是可以直接通過這個(gè)轉(zhuǎn)換替換成.kt的Code,但是,其中也會(huì)有很多坑,需要具體情況具體分析才行
④查看Kotlin代碼生成的字節(jié)碼文件和編譯成的.java文件(僅供參考)
點(diǎn)擊即可生成.java文件(反編譯得到,有時(shí)候看不懂Kotlin代碼可以參考一下)
4 Kotlin常見方言
①不再需要的findViewById
告別findViewById,kotlin會(huì)自動(dòng)生成View相關(guān)的code(名稱為布局的id),不再需要我們手動(dòng)findViewById了(實(shí)現(xiàn)可看反編譯的.java文件),同時(shí)點(diǎn)擊變量可以自動(dòng)跳轉(zhuǎn)到布局,不局限于Activity,自定義View中也可以這樣使用
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
main_btn_hw.setOnClickListener(this)
main_btn_basic1.setOnClickListener(this)
main_btn_basic2.setOnClickListener(this)
}
②更靈活的字符串
直接通過$號(hào)引用屬性或${}區(qū)間引用對(duì)象方法,通過反編譯代碼可以看到,這一實(shí)現(xiàn)過程的拼接是通過StringBuild實(shí)現(xiàn),不需要擔(dān)心產(chǎn)生額外多的對(duì)象問題
fun visibleStrCode() {
val a = "a"
val b = "b"
val c = "c"
val d = "d"
val v = arrayListOf<String>()
val alphabet = "a : $a -b : $b - c : $c - d : $d -- ${returnStr()}"
val sizeStr = "size is ${v.size}"
}
③Null Pointer Exception
只要一個(gè)對(duì)象或變量沒有被顯式的聲明可以為null,那么之后所有null的賦值都被視作是非法的,無法通過編譯,對(duì)非null值做判空,會(huì)有warning提示
fun visibleNPEMethod() {
var nullA2: A? = null
var notNullA1 = A()
notNullA1 = nullA2 //不可被賦予一個(gè)null對(duì)象
notNullA1 = null //不可賦值為null
if(notNullA1 == null){//warning
}
println(notNullA1.myStr)
//使用一個(gè)null對(duì)象,需要顯式的做空判斷,否則會(huì)視作是非法的,無法通過編譯
println(nullA2.myStr)
//可以通過字面值? Elvis 運(yùn)算符來表示,賦值給一個(gè)不能為null的屬性,
//在此時(shí)要顯示指定一個(gè)默認(rèn)值
//賦值給一個(gè)不能為null的值,
val a3: A = nullA2 ?: A()
//但是不能這樣訪問屬性
val str: String = nullA2?.myStr : "null"
//!! 忽略這個(gè)空判斷,有空指針危險(xiǎn)
val str2 : String = nullA2!!.myStr
//判空后會(huì)視作不為null的對(duì)象
if (nullA2 != null) {
println(nullA2.myStr)
//①
if (nullA2 != null) {//后續(xù)無需判空,會(huì)有warning警告
//do something
}
//②使用let函數(shù),這樣保證其中不為null
nullA2.let {
//這里it指向的就是nullA2
it.myStr
}
}
}
對(duì)于一個(gè)可能為null的對(duì)象,在上面的代碼,是有一些需要注意的細(xì)節(jié)
④更方便的類型轉(zhuǎn)換
is 關(guān)鍵字,當(dāng)某個(gè)對(duì)象通過is關(guān)鍵字進(jìn)行類型判斷后,可以在之后的區(qū)間內(nèi)直接當(dāng)做對(duì)應(yīng)對(duì)象類型做處理,例如使用相關(guān)的方法
搭配When關(guān)鍵字會(huì)更好用
fun classCastMethod(superClz: SuperClz) {
when (superClz) {
is A -> {
superClz.getA()
}
is B -> superClz.getB()
is C -> superClz.getC()
}
if (superClz is A) {
superClz.getA()
}
}
這里的ABC,分別是一個(gè)類,類中獨(dú)有的方法就是getX()
⑤更實(shí)用的Bean(data數(shù)據(jù)類)
使用data關(guān)鍵字修飾的class類
會(huì)自動(dòng)生成set,get,copy,equals等方法
不用再像java一樣顯式的重寫
同時(shí)還可以方便的使用組成方法
當(dāng)然,如果有需求也可以重寫進(jìn)行覆蓋
data class Thai(val name: String, var sex: Int)
就這樣一個(gè)簡單的類,在我們使用可以很方便的獲取一些信息:
@Test
fun testDataClz() {
val man = 1
val woMan = 2
val unknow = 3
//有一個(gè)泰國人,性別男
var aTiChaSir = Thai("阿提查*春娜依", man)
//轉(zhuǎn)換一下
val aTiChaLady = aTiChaSir.copy(sex = woMan)
//快速獲取屬性
val (name1, sex1) = aTiChaLady//這里獲取的屬性不是通過名字,而是屬性順序
println("sex:$name1 --name:$sex1")
}
⑥延遲加載lazy
Kotlin允許對(duì)一個(gè)屬性進(jìn)行延遲加載,使用by操作符+lazy函數(shù)可以進(jìn)行
值得注意的是,這一操作只允許對(duì)val修飾的屬性
可選:可以指定是否線程安全(默認(rèn))
NOTE:PUBLICATION:允許多個(gè)結(jié)果的可能返回,但只取第一個(gè)結(jié)果
//延遲加載,必須是val修飾
//只會(huì)執(zhí)行一次,
//可選:線程是否安全
val lazyStr: String by lazy(LazyThreadSafetyMode.PUBLICATION) {
println("lazy init method")
"I'm a lazyStr"
}
Test結(jié)果:
@Test
fun testLazyMethod() {
println(ClassCastClz.lazyStr)
println(ClassCastClz.lazyStr)
}
⑦With關(guān)鍵字,更方便的方法調(diào)用
使用該關(guān)鍵字可以在一定區(qū)間,可以很方便的調(diào)用該對(duì)象的方法和屬性,就像在這個(gè)方法中一樣
@Test
fun testKeywordWith() {
val withClzObj = KeyWith()
with(withClzObj) {
println(numberProperty + 100)
preper()
onCreate()
onStart()
onResume()
}
}
⑧l(xiāng)ambda表達(dá)式
fun lambdaMethod() {
//顯式指定名稱
val viewClickListener = View.OnClickListener {
// myView: View? -> //可選,重寫對(duì)應(yīng)的參數(shù),指定名稱,默認(rèn)為it
// if(myView != null){
// println(myView.id)
// }
println(it.id)
}
//不指定名稱,交給編譯器去解析
val anonymityClickListener = { v: View? ->
if (v != null) {
println(v.id)
}
}
val v = View(null)
v.setOnClickListener(anonymityClickListener)
}
}
這里用View.onClickListener做示例
主要寫法有兩種,?①顯式的指定lambad表達(dá)式類型
②交給編譯器去推斷,需要注意的是,交給編譯期,需要參數(shù)對(duì)應(yīng),類型一致否則無法正確的解析
⑨類擴(kuò)展方法
Kotlin支持對(duì)一個(gè)類進(jìn)行額外的方法拓展,這使得你在使用該類可以不用再創(chuàng)建額外的子類來擴(kuò)展其方法,無縫使用,更方便(當(dāng)然,也支持類的屬性擴(kuò)展)
接收者是可以為?,表示可以為null的類型,這樣的話,在設(shè)計(jì)擴(kuò)展方法時(shí),能有更靈活的code編寫
我這里寫了幾個(gè)簡單的栗子
/**
* 拿到文本的高度
*/
fun TextView.getTextHeight(): Float {
//可以直接獲取到該類的屬性
val fontMetrics = paint.fontMetrics
return fontMetrics.bottom - fontMetrics.top;
}
/**
* 字符串是否是null
*/
fun String?.isNullStr(): Boolean {
return this == null || "" == this || "null" == this
}
/**
* 集合是否是空
*/
fun List<*>?.isNullEmpty(): Boolean {
return this == null || this.isEmpty()
}
/**
* 通過Context直接拿Dimension
*/
fun Context.getDimension(resId : Int):Float{
return this.resources.getDimension(resId)
}
5,Kotlin與Java代碼的相互調(diào)用
這可是Kotlin的一大賣點(diǎn)!!!
這里簡單介紹一下Java調(diào)用Kotlin,前文中Kotlin調(diào)用Java已經(jīng)出現(xiàn)過很多次,不再累贅了
基本可以做到無縫調(diào)用
但是值得注意的是,在java代碼中調(diào)用Kotlin代碼,部分特性會(huì)不再支持
比如:空安全
public void method() {
//擴(kuò)展方法可以直接看做一個(gè) static final修飾的方法
boolean isNull = ExtendMethodListKt.isNullStr("aabb");
//對(duì)象可以直接創(chuàng)建
LambdaClaz ccc = new LambdaClaz();
//調(diào)用屬性需要調(diào)用對(duì)應(yīng)的set,get方法
View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
}
};
ccc.setMyClickListener(clickListener);
View.OnClickListener runnableInherit = ccc.getMyClickListener();
//伴生對(duì)象可以直接看做一個(gè)靜態(tài)對(duì)象
LambdaClaz.Companion.lambdaMethod();
}
6小結(jié)
以上就是我這段時(shí)間關(guān)于Kotlin的一次小小的調(diào)查,文中很多代碼比較簡單,隨心寫的一些code,就沒有傳項(xiàng)目到GitHub上了,如果有所疑問,歡迎在評(píng)論區(qū)中留言探討.
對(duì)于Kotlin,我個(gè)人的看法:
五級(jí)評(píng)分,Level4,看好,如果在項(xiàng)目有機(jī)會(huì),我會(huì)考慮使用