綱要
- 前言
- Kotlin是什么?
- 為什么使用Kotlin?
- Kotlin常用特性有哪些(與Java比較)?
- 如何在開發(fā)中集成Kotlin?
- 使用Kotlin常見問題有哪些?
前言
從2017年秋季接觸Kotlin以來,開始3個月寫了一些學習Demo,最近半年才開始用Kotlin開發(fā)企業(yè)級的APP,遇到了一點坑,但整體感覺:簡潔、高效,以至于現(xiàn)在絲毫不想寫又臭又長的Java代碼。
還在堅持寫Java的同學不妨試試Kotlin,一定會讓你流連忘返、樂不思Java ,:p。
Kotlin是什么?
簡介
Kotlin是一種在Java虛擬機上運行的靜態(tài)類型編程語言,它也可以被編譯成為JavaScript源代碼。
主要由JetBrains的圣彼得堡團隊所開發(fā),其名稱來自于圣彼得堡附近的科特林島。
靜態(tài)動態(tài)類型編程語言:通俗講
靜態(tài)類型指的是編譯器在compile time執(zhí)行類型檢查,動態(tài)類型指的是編譯器(虛擬機)在runtime執(zhí)行類型檢查
JVM語言 Kotlin vs Java
Kotlin和Java源文件都需要先編譯成符合JVM規(guī)范的字節(jié)碼文件,才能夠在JVM運行。因此,本質(zhì)上講
- Java能做的,Kotlin都能做,反之亦然。
- Java和Kotlin能夠相互轉(zhuǎn)換。通過字節(jié)碼文件可以反編譯為對方的源碼文件。

應用范圍

JVM-Java服務端開發(fā)(替代Java)
Android
Browser-JavaScript開發(fā)(替代JavaScript)
Native-C相關開發(fā)(替代C、Object-C和Swift)
歷史
- 2011年7月-JetBrains推出Kotlin項目
- 2016年2月-發(fā)布v1.0版本
- 2017年11月28日-v1.2
- 2018年6月14日-v1.2.50
Google支持情況
- Google I/O 2017-Google宣布在Android上為Kotlin提供最佳支持
- Google I/O 2018-Android高級開發(fā)者使用Kotlin的人數(shù)達到35%
為什么使用Kotlin?
通用理由

參考示例見官方
https://www.kotlincn.net/
使用Kotlin開發(fā)Android的理由
- 兼容性:Kotlin 與 JDK 6 完全兼容,保障了 Kotlin 應用程序可以在較舊的 Android 設備上運行而無任何問題。Kotlin 工具在 Android Studio 中會完全支持,并且兼容 Android 構建系統(tǒng)。
- 性能:由于非常相似的字節(jié)碼結構,Kotlin 應用程序的運行速度與 Java 類似。 隨著 Kotlin 對內(nèi)聯(lián)函數(shù)的支持,使用 lambda 表達式的代碼通常比用 Java 寫的代碼運行得更快。
- 互操作性:Kotlin 可與 Java 進行 100% 的互操作,允許在 Kotlin 應用程序中使用所有現(xiàn)有的 Android 庫 。這包括注解處理,所以數(shù)據(jù)綁定和 Dagger 也是一樣。
- 占用:Kotlin 具有非常緊湊的運行時庫,可以通過使用 ProGuard 進一步減少。 在實際應用程序中,Kotlin 運行時只增加幾百個方法以及 .apk 文件不到 100K 大小。
- 編譯時長:Kotlin 支持高效的增量編譯,所以對于清理構建會有額外的開銷,增量構建通常與 Java 一樣快或者更快。
- 學習曲線:對于 Java 開發(fā)人員,Kotlin 入門很容易。包含在 Kotlin 插件中的自動 Java 到 Kotlin 的轉(zhuǎn)換器有助于邁出第一步。Kotlin 心印 通過一系列互動練習提供了語言主要功能的指南。
另外的理由
- 不用寫煩人的findViewById
- Android Studio支持Java To Kotlin一鍵轉(zhuǎn)換
Kotlin常用特性有哪些(與Java比較)?
具體語法可見Kotlin官網(wǎng),或對應的中文版
以下主要說一下常用的語法或特性
基本語法
定義變量
局部變量-kotlin
fun testDefination() {
// 不可變
val a: Int = 1 // 立即賦值
val b = 2 // 自動推斷出 `Int` 類型
val c: Int // 如果沒有初始值類型不能省略
c = 3 // 明確賦值
// 可變
var x = 5 // 自動推斷出 `Int` 類型
x += 1
}
局部變量-java
public void testDefination() {
final int a = 1;// 可變
int b = 1;// 不可變
}
成員變量的懶加載和延遲加載-kotlin
// 懶加載
private val freshman by lazy {
Person("feifei", 18, true)
}
// 延遲加載。定義成員變量時必須初始化,但不想初始化或不想引入空時,可以使用延遲加載
private lateinit var old: Person
成員變量的懶加載和延遲加載-java?
字符串模板
kotlin
@Test fun testStringTemplates() {
val age = 12
val name = "feifei"
print("name -> $name, age -> $age")
}
java
public void testPrintString() {
String name = "feifei";
int age = 18;
System.out.print("name -> " + name + ",age ->" + age);
}
Elvis 操作符?
// 判空。如果str=null,會打?。篖ength = null
@Test fun testNull (str: String?) {
println("Length = " + str?.length)
}
// 類型轉(zhuǎn)換
@Test fun testCast() {
val l2 = listOf("A",1,3,6,8,'c')
l2.forEach { println(it as? Int) }
}
斷言操作符!!
private var p1: Person? = null
@Test
fun testAssert() {
p1 = Person("feifei", 18, true)
println(p1!!.name)
}
條件表達式
@Test
fun testCondition() {
// 空條件
val files = File("Test").listFiles()
println(files?.size ?: "empty")
// if-else
println("max -> ${maxOf(1,2)}")
// when
val items = listOf("apple", "banana", "kiwifruit", "grape", "pear", "ab...")
when {
"orange" in items -> println("juicy")
"apple" in items -> println("apple is fine too")
}
// when
describe(items[0])
}
fun maxOf(a: Int, b: Int): Int {
return if (a > b) {
a
} else {
b
}
}
fun describe(obj: Any): String =
when (obj) {
1 -> "One"
"Hello" -> "Greeting"
is Long -> "Long"
!is String -> "Not a string"
else -> "Unknown"
}
循環(huán)表達式和集合
@Test
fun testLoop() {
val items = listOf("apple", "banana", "kiwifruit", "grape", "pear", "ab...")
// for loop
testForLoop(items)
// collection
testCollection(items)
}
private fun testForLoop(items: List<String>) {
for (item in items) {
println(item)
}
for (index in items.indices) {
println("item at $index is ${items[index]}")
}
for (index in 0 until items.size) {
println("item at $index is ${items[index]}")
}
for (index in items.size - 1 downTo 0 step 2) {
println("item at $index is ${items[index]}")
}
}
private fun testCollection(items: List<String>) {
items.filter { it.startsWith("a") }
.sortedBy { it }
.map { it.toUpperCase() }
.forEach { println(it) }
}
類型檢測
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// `obj` 在該條件分支內(nèi)自動轉(zhuǎn)換成 `String`
return obj.length
}
// 在離開類型檢測分支后,`obj` 仍然是 `Any` 類型
return null
}
默認參數(shù)
@Test
fun testDefaultArgs() {
println(createPerson("feifei1"))
println(createPerson("feifei2", 12))
println(createPerson("feifei3", 12, true))
}
private fun createPerson(name:String, age:Int = 0, isMale: Boolean = false):Person {
return Person(name, age, isMale)
}
數(shù)據(jù)模型
// 會為 Customer 類提供以下功能:
// 所有屬性的 getters (對于 var 定義的還有 setters)
// equals()/hashCode()/toString()/copy()等
data class Customer(val name: String, val email: String)
單例
object Resource {
val name = "Name"
}
常量
class KotlinSyntax {
companion object {
const val PI = 3.14
}
}
// 或者
object Resource {
val name = "Name"
const val PI = 3.14
}
方法作為其他方法的參數(shù)
一般用于回調(diào)
// 場景,有一個輪播條,點擊其中一個進入詳情
// 定義一個adapter,傳入值和對調(diào)函數(shù)
class BannerPagerAdapter (var srcs: List<String>,
private val callback: (position: Int)->Unit) : PagerAdapter() {
override fun instantiateItem(container: ViewGroup, position: Int): Any {
val view = LayoutInflater.from(container.context).inflate(R.layout.view_home_headline, container, false)
val tvHeard = view.findViewById<TextView>(R.id.iv_headline)
// 設置點擊監(jiān)聽
tvHeard.setOnClickListener({callback(srcs[position])})
container.addView(view)
return view
}
// ...
}
// 在Activity中設置
private val bannerAdapter by lazy {
BannerPagerAdapter(list_banner, callback = { title ->
toBannerDetail(title)
})
}
private fun toBannerDetail(title: String) {
// to detail
}
// or 簡單的例子
@Test
fun testHighOrderFunc() {
val items = listOf("a", "b", "c")
wrapDoSomething { println(items) }
}
private fun wrapDoSomething(doSomething:()->Unit) {
println("-->")
doSomething()
println("<--")
}
范圍外 run,let,with,apply
class Turtle {
fun penDown(){}
fun penUp(){}
fun turn(degrees: Double){}
fun forward(pixels: Double){}
}
// 對一個對象實例調(diào)用多個方法 (with)
@Test
fun testWith() {
val myTurtle = Turtle()
with(myTurtle) { // 畫一個 100 像素的正方形
penDown()
for(i in 1..4) {
forward(100.0)
turn(90.0)
}
penUp()
}
}
Java調(diào)用Kotlin
object KotlinObject {
const val PI = 3.14
fun max(a: Int, b: Int): Int {
return if (a > b) {
a
} else {
b
}
}
}
class KotlinClass {
companion object {
const val PI = 3.14
fun max(a: Int, b: Int): Int {
return if (a > b) {
a
} else {
b
}
}
}
}
public void useKotlin() {
// use object
System.out.print(KotlinObject.PI);
System.out.print(KotlinObject.INSTANCE.max(1,2));
// use class static const or fun
System.out.print(KotlinClass.PI);
System.out.print(KotlinClass.Companion.max(1,2));
}
用于Android開發(fā)的工具
- Kotlin Android 擴展是一個編譯器擴展, 可以讓你擺脫代碼中的
findViewById()調(diào)用,并將其替換為合成的編譯器生成的屬性。- Anko 是一個提供圍繞 Android API 的 Kotlin 友好的包裝器的庫 ,以及一個可以用 Kotlin 代碼替換布局 .xml 文件的 DSL。
如何在開發(fā)中使用Kotlin
非Android開發(fā)
Android開發(fā)
創(chuàng)建新項目
Android Studio 3.0+完全支持kotlin,創(chuàng)建項目的時候,默認勾選支持Kotlin,創(chuàng)建完項目后會自動在gradle文件中引入插件和擴展插件。

創(chuàng)建完工程后,工程gradle文件中

應用Module gradle文件中

Java 轉(zhuǎn) Kotlin
- 切到要轉(zhuǎn)換的Java文件
- Android Studio菜單 Code -> ‘Convert Java File to Kotlin File’, 或 Mac環(huán)境下,雙擊Shite鍵,輸入 covert java....出現(xiàn)‘Convert Java File to Kotlin File’選項。
Java轉(zhuǎn)kotlin的常見問題
一般而言可以直接轉(zhuǎn)換,無需修改,但有時需要手動修改,一般在如下幾個地方出現(xiàn):
-
邏輯操作符。kotlin中只有Int類型的值才能直接進行邏輯運算,其他類型如Byte要轉(zhuǎn)為Int之后才能進行邏輯運算。且,kotlin中的邏輯運算是作為方法出現(xiàn)的。
邏輯運算 Java vs Kotlin 單行賦值后進行比較
這個在讀流操作時經(jīng)常出現(xiàn)
private void readIS(InputStream is) throws Exception {
int len = 0;
byte[] bytes = new byte[1024];
OutputStream os = new FileOutputStream("/file/text.txt");
while ((len = is.read(bytes)) != -1) {
os.write(bytes, 0, len);
}
}
直接轉(zhuǎn)換成kotlin是
@Throws(Exception::class)
private fun readIS(`is`: InputStream) { // is是kotlin關鍵字,所有做了處理
var len = 0
val bytes = ByteArray(1024)
val os = FileOutputStream("/file/text.txt")
while ((len = `is`.read(bytes)) != -1) { // 這行報語法錯誤
os.write(bytes, 0, len)
}
}
// 稍作修改,消除語法錯誤
@Throws(Exception::class)
private fun readIS(`is`: InputStream) {
var len = 0
val bytes = ByteArray(1024)
val os = FileOutputStream("/file/text.txt")
len = `is`.read(bytes)
while (len != -1) {
os.write(bytes, 0, len)
len = `is`.read(bytes)
}
}
使用Kotlin常見問題有哪些?
待續(xù)
參考
Kotlin官網(wǎng)
Kotlin中文網(wǎng)
Android開發(fā)者官方
Android Kotlin Guides
Kotlin_Tips
Kotlin簡單編譯流程
Kotlin編譯過程分析
