《Kotin 編程思想·實戰(zhàn)》
《Kotlin極簡教程》正式上架:
點擊這里 > 去京東商城購買閱讀
點擊這里 > 去天貓商城購買閱讀
1 JVM語言家族概覽
1.1 編程語言簡史
1.2 程序執(zhí)行的三種方式
1.2.1 編譯執(zhí)行
1.2.2 解釋執(zhí)行
1.2.3 虛擬機執(zhí)行
1.3 JVM概述
1.3.1 Java源代碼編譯執(zhí)行過程
1.3.2 Java Class文件簡介
1.3.3 JVM字節(jié)碼執(zhí)行過程
1.4 JVM語言家族
1.4.1 Scala
1.4.2 Groovy
1.4.3 Clojure
1.4.4 Kotlin
1.4.5 Xtend
Xtend是Eclipse推出的一個新的JVM語言盏浙,并無意替代Java,而是以己之長補Java之短,精簡代碼蒙挑,無類型夹供,改進可讀和維護码党。Eclipse Xtend可以編譯成可讀的Java代碼呕诉,類似CoffeeScript之于Javascript猖毫。
靜態(tài)類型
特點
擴展方法 :加強封閉類型的新功能。
Lambda表達式:匿名函數(shù)文字簡潔的語法镐依。
將lambda表達式編譯成匿名內(nèi)部類匹涮。
運算符重載:讓庫更表達。
強大的交換機的表達:類型與隱式類型轉(zhuǎn)換開關槐壳。
多個調(diào)度:即多態(tài)方法調(diào)用然低。
模板表達式:智能空間處理。
報表:一切都是表達式宏粤。
屬性:訪問和定義getter和setter方法的速記法脚翘。
局部類型推理:很少需要寫下類型簽名了。
全面支持Java的泛型:包括所有的一致性和轉(zhuǎn)換規(guī)則绍哎。
類型系統(tǒng):Xtend的靜態(tài)類型是不錯的来农,因為它允許更好的靜態(tài)分析和基于類型信息的更好的工具。然而崇堰,缺點是額外的復雜性
2 Kotlin簡介
2.1 kotlin簡史
2.2 快速學習工具
2.2.1 云端IDE
2.2.2 本地命令行環(huán)境搭建
2.2.3 Kotlin REPL
2.2.4 使用IntelliJ IDEA
2.2.5 使用Gradle構(gòu)建工程
3 快速開始:HelloWorld
3.1 命令行的HelloWorld
3.2 應用程序版HelloWorld
3.3 Web RESTFul HelloWorld
3.4 Android版的HelloWorld
3.5 JavaScript(Canvas) 版HelloWorld
4 kotlinc編譯過程分析
4.1 kotlinc執(zhí)行原理分析
4.2 kotlin代碼執(zhí)行過程
4.3 Kt.class與Java.class區(qū)別
5 語言基礎
5.1 基礎語法
5.1.1 包(package)
package打包與import導包
源文件可以不需要匹配目錄和包沃于,源文件可以放在任何文件目錄
如果沒有任何包聲明的話,則當中的代碼都屬于默認包海诲,導入時包名即為函數(shù)名繁莹!
比如:import shortToast
另外你還可以在導入類的時候為類設置一個別名,比如:
import java.util.Date as d
直接在文件中寫一堆fun方法特幔!
kotlin中因為可以使用擴展方法咨演,所以可以連class和interface都不寫,
5.1.2 變量
變量作用域
聲明變量
val
var
val定義常量和var定義變量蚯斯,默認都是private的薄风,比如
定義:val a =123, var b = 321,打開生成的.class文件可以看到:
private私有拍嵌,且默認寫了公有的getter和setter方法遭赂。
5.1.3 表達式
range
return
throw
三元表達式
Lambda表達式
this表達式
super表達式
5.1.4 代碼塊
5.1.5 分支控制流
if表達式
判斷結(jié)構(gòu)(條件表達式)
Java int max = a>b?a:b
Kotlin: val max = if (a>b) a else b
在if語句塊的最后可以自動返回最后一行表達式的值,而不需要寫return
fun ifExample(x: Int, y: Int) {
val result = if (x >= y) {
println("Condition ok.")
true
} else {
println("Condition else.")
false
}
println("Result $result")
}
when表達式
fun whenExample(userType: Int) {
when (userType) {
0 -> println("Registered user")
1 -> print("Administrator")
else -> {
println("Unknown")
}
}
}
fun whenExample2(userType: Int) {
when (userType) {
0, 1 -> println("Welcome user.")
else -> println("Permission denied.")
}
}
fun whenExample3(userType: Int) {
when (userType) {
filterUserType(userType) -> {
println("Subtype ok")
whenExample2(userType)
}
else -> print("Subtype not ok")
}
}
fun filterUserType(userType: Int): Int {
if (userType >= 0 && userType < 2) {
return userType;
}
return -1
}
fun whenExample4(x: Int) {
val from = 0
val to = 100
when (x) {
in from..to -> println("PRECISE")
in (from / 2)..(to / 2) -> print("VERY PRECISE")
50 -> print("STRAIGHT IN TARGET")
else -> print("MISSED")
}
}
fun whenExample5(fullName: String) {
val isJohn = when (fullName) {
is String -> fullName.startsWith("John ")
else -> false
}
}
fun whenExample6(fullName: String) {
when {
fullName.length == 0 -> println("Please enter your name.")
fullName.substring(0, 2).equals("X ") -> println("Hello Mr. X")
fullName.startsWith("John ") && !fullName.endsWith(" Smith") -> println("Hello John!")
fullName.endsWith(" Smith") -> println("Hello agent Smith.")
else -> println("Only secret agents allowed!")
}
}
5.1.6 循環(huán)
while循環(huán)
for循環(huán)
Kotlin中的while與do-while横辆,break撇他,continue與Java中的類似,不過Kotlin中多了個好玩的東西:
Ranages狈蚤,包含與范圍有關的函數(shù)操作符
Ranages
在范圍內(nèi)與不在范圍內(nèi)
fun main(array: Array<String>) {
for ((index, value) in array.withIndex()) {
println("[ value ]")
}
val a1 = 1
val a2 = 2
val b1 = if(a1 in 0..9) true else false
val b2 = if(a2 !in 10..20 ) true else false
println(b1)
println(b2)
val str1 = "Hello"
val str2 = "Hello,Wolrd"
if(str1 in str2) println(str1 + " in " + str2) else println(str1 + " is not in " + str2)
if(str1 in "Hello".."Kotlin") println(str1 + " in " + "Hello".."Kotlin") else println(str1 + " is not in " + "Hello".."Kotlin")
}
順序遍歷
val arr = Array(10,{n->n})
arr.forEach(::print)
println()
arr.forEach{
it->print(it.toString() + " ")
}
println()
for(e in arr) print(e)
println()
for(i in 0..arr.lastIndex) print(arr[i].toString() + " ")
println()
你也可以調(diào)lastIndex來獲得最后的下標困肩,寫成if(i in 0..array.lastIndex)
如果你不想順著遍歷,想反過來遍歷脆侮,可以利用downTo (遞減)關鍵字僻弹,從最大值到最小值遞減!
for(i in 9 downTo 5) print(arr[i])
println()
可能你還想隔著遍歷他嚷,比如只遍歷:10,7,4,1,可以用 step (步長)關鍵字!后面跟著的是步長筋蓖,
比如你可以寫成小數(shù)0.1這樣也行卸耘,示例:
for(i in 9 downTo 3 step 3) print(arr[i])
倒序遍歷
5.1.7 代碼注釋
5.1.8 異常
Kotlin中所有的Exception都繼承了Throwable,含有一個message且未經(jīng)檢查粘咖。
這表示不會強迫我們在任何地方使用try/catch蚣抗,而Java中如果某個方法拋出
了Exception,就需要用try-catch包圍代碼塊瓮下。
Kotlin拋出異常和try-catch-finally和Java中的類似翰铡!但是Kotlin中throw和try都是表達式,
意味著他們可以賦值給某個變量讽坏,這一點在處理邊界問題的時候很有用锭魔!代碼示例:
class ExceptionExamples {
fun exceptionExmple() {
try {
// do something ...
} catch (e: KotlinNullPointerException) {
// handle exception
} finally {
// do something ...
}
}
// Try / Catch is expression!
fun exceptionExample2(): Int {
return try {
// do something
0
} catch (e: KotlinNullPointerException) {
// handle exception
-1
}
}
}
5.2 標識符
5.2.1 修飾符
訪問權(quán)限
public:默認,總是可見
internal:同模塊可見
private:聲明范圍與同模塊的子作用域可見
protected:類似于private路呜,但對子類也可見
5.2.2 關鍵保留字
var:定義變量
val:定義常量
fun:定義方法
Unit:默認方法返回值迷捧,類似于Java中的void,可以理解成返回沒什么用的值
vararg:可變參數(shù)
如果是可變參數(shù)的話胀葱,可以使用 vararg 關鍵字修飾
fun sum(vararg args: Int) {
var sum = 0
for (x in args) {
sum += x
}
println("Sum: $sum")
}
fun trySum(){
sum(1, 3, 6, 10, 1, 2, 3, 4)
}
$:字符串模板(取值)
位運算符:or(按位或)漠秋,and(按位與),shl(有符號左移)抵屿,shr(有符號右移)庆锦,
ushr(無符號右移),xor(按位異或)轧葛,inv(按位取反)
in:在某個范圍中
downTo:遞減搂抒,循環(huán)時可用,每次減1
step:步長朝群,循環(huán)時可用燕耿,設置每次循環(huán)的增加或減少的量
when:Kotlin中增強版的switch,可以匹配值姜胖,范圍誉帅,類型與參數(shù)
is:判斷類型用,類似于Java中的instanceof()
5.2.3 運算符
5.2.4 賦值符
5.3 函數(shù)
5.3.1 main函數(shù)
5.3.2 定義函數(shù)
使用 fun 關鍵字來聲明
如果沒有訪問控制符修飾的fun默認是public final的右莱!
返回值:Unit
擴展函數(shù)
直接定義在文件中蚜锨,而不需要依賴于任何的類的函數(shù)
成員函數(shù)
寫在class或object中的函數(shù)
5.3.3 包級函數(shù)
5.3.4 Lambda表達式
// lambda寫法1
val runnable3 = Runnable { ->
println("I'm a Lambda")
}
// lambda寫法2
val runnable4 = { println("I'm a Lambda") }
Thread(runnable4).start()
函數(shù)式接口(functional interface)
只包含一個抽象方法的接口
Java標準庫中的java.lang.Runnable和java.util.Comparator
public void runThread() {
new Thread(new Runnable() {
public void run() {
System.out.println("Run!");
}
}).start();
}
public void runThreadUseLambda() {
new Thread(() -> {
System.out.println("Run!");
}).start();
}
Collections.sort(list, (x, y) -> y - x);
List input = Arrays.asList(new String[] {"apple", "orange", "pear"});
input.forEach((v) -> System.out.println(v));
input.forEach(System.out::println);
5.3.5 閉包
5.3.6 匿名函數(shù)
// new 一個線程
// 匿名類寫法
val runnable1 = object : Runnable{
override fun run() {
println("I'm an anonymous class")
}
}
// 函數(shù)寫法, 略像js
val runnable2 = fun (){
println("I'm a function")
}
5.4 特色功能
5.4.1 函數(shù)拓展和屬性拓展(Extensions)
fun main(args: Array<String>) {
val list = listOf("1", "2", "3", "4")
// 函數(shù)拓展
list.myForEach { println(it) }
// 屬性拓展
println("last: ${list.lastItem}")
}
/**
- 拓展 List 類, 加一個自定義的遍歷方法
*/
fun <T> List<T>.myForEach(doTask: (T) -> Unit){
for(item in this)
doTask(item)
}
/**
- 拓展 List 類, 加一個自定義的長度屬性
*/
val <T> List<T>.lastItem: T
get() = get(size - 1)
// 輸出:
1
2
3
4
last: 4
class Employee {
fun name(): String {
return "Employee name"
}
}
class ExtendedFunctionalityExample(val e: Employee) {
// We extended Employee class with function that does not exist in original class!
fun Employee.age(): Int {
return 25
}
fun tryExtendedEmployeeExample() {
println("Name: ${e.name()}, Age: ${e.age()}")
}
}
5.4.2 屬性代理
以懶加載為例,lazySum可能需要復雜的運算慢蜓,我們把它代理給lazy亚再。 可以看到,只有第一次加載進行了計算晨抡,之后都是直接取值氛悬,提高了效率则剃。
val lazySum: Int by lazy {
println("begin compute lazySum ...")
var sum = 0
for (i in 0..100)
sum += i
println("lazySum computed!\n")
sum // 返回計算結(jié)果
}
fun main(args: Array<String>) {
println(lazySum)
println(lazySum)
}
// 輸出:
begin compute lazySum ...
lazySum computed!
5050
5050
5.4.3 委托(Delegate)
5.4.4 空指針安全
空對象檢查Null Check
var mNullable: String? = null
var mNonNull: String = "mNonNull"
fun testNull(){
println("testNull: ")
println(mNullable?.length)
println(mNonNull.length)
println()
}
// 輸出:
testNull:
null
8
// java 風格,判空
if(mNullable != null)
mNullable.length
// kotlin 語法糖如捅,判空(推薦)
mNullable?.length
null check實現(xiàn)原理簡析
空類型強轉(zhuǎn)為非空類型
var user: User? = getUser()
user!!.name = "Jack"
5.4.5 Lazy Evaluation
class UsesLazy {
val myLazyValue: String by lazy {
println("I am initializing this lazy value!")
"My lazy value!"
}
}
fun useLazy(){
val usesLazy: UsesLazy = UsesLazy()
val a: String = usesLazy.myLazyValue
val b: String = usesLazy.myLazyValue
val c: String = usesLazy.myLazyValue
}
6 類型系統(tǒng)
6.1 編譯時類型與運行時類型
6.2 根類型Any
對象相等性
6.3 基本類型(Primitive Types)
6.3.1 Number: 包含整型與浮點型等
kotlin.Byte
kotlin.Short
kotlin.Int
kotlin.Long
kotlin.Float
kotlin.Double
6.3.2 Char: 字符類型(Character)
6.3.3 Boolean: 布爾類型
6.3.4 String: 字符串類型
字符串常量
字符串函數(shù)
字符串模板
轉(zhuǎn)義字符串
Kotlin居然沒有自動轉(zhuǎn)型
for(i in 0..arr.lastIndex) print(arr[i] + " ") 不能自動轉(zhuǎn)型棍现,這樣寫代碼多麻煩
for(i in 0..arr.lastIndex) print(arr[i].toString() + " ")
6.3.5 Array: 數(shù)組類型
原生數(shù)組類型
創(chuàng)建數(shù)組
定長數(shù)組:val fixedSizeArray = arrayOfNulls<Int>(10)
空數(shù)組: val empty = emptyArray<Int>()
裝箱操作:val arr = arrayOf(1, 2, 3) //還有其他比如IntArrayOf,BooleanArrayOf等
閉包初始化:
val arr = Array(100, {num -> num})
for(i in 0..99) println(arr[i])
訪問數(shù)組
使用[]
[]訪問數(shù)組元素在這里實際上是進行了操作符的
重載镜遣,調(diào)用的其實是Array類的getter和setter方法己肮,但是編譯成字節(jié)碼的時候會進行優(yōu)化,
變成直接訪問數(shù)組的內(nèi)存地址悲关,所以并不會造成性能損失谎僻!
遍歷數(shù)組
foreach遍歷
for(e in arr) println(e)
根據(jù)下標遍歷
for(i in arr.indices) println(arr[i])
indices代表下標!范圍:(0 <= indices < 數(shù)組size)
6.4 特殊類型
kotlin.Any
kotlin.Nothing
kotlin.Unit
kotlin.KClass<T>
6.5 可空類型(Nullable Types)
6.6 函數(shù)類型( Functional Types)
閉包類型
6.7 類型檢測
is運算符
as運算符
6.8 類型轉(zhuǎn)換
6.9 類型別名typealias
6.10 泛型
fun <T> genericFunctionsExample(x: T){
println("Value: $x")
}
fun tryGenericFunctionsExampe(){
genericFunctionsExample(5)
genericFunctionsExample("Some word!")
genericFunctionsExample('c')
genericFunctionsExample(5.55)
}
7 面向?qū)ο缶幊蹋∣OP)
7.1 面向?qū)ο笏枷?/p>
7.2 類與繼承
7.2.1 類
類的橫向分類
抽象類
接口類
枚舉類
注解類
靜態(tài)類與伴生對象
sealed 密封類
sealed class SuperEnum {
class Human(val race: String) : SuperEnum()
class Animal(val specie: String, val legsCount: Int) : SuperEnum()
object Bacteria : SuperEnum()
}
fun trySuperEnum(superEnum: SuperEnum): String = when (superEnum) {
is SuperEnum.Human -> "Human {superEnum.specie} with ${superEnum.legsCount} legs."
is SuperEnum.Bacteria -> "Some micro organism ..."
}
data 數(shù)據(jù)類
data class Person(val name: String, val age: Int){}
fun tryDataClassCopying(){
val p = Person("John Smith", 1985)
val p2 = p.copy()
val p3 = p.copy(age = 1990)
val p4 = p.copy("John Doe")
println(p)
println(p2)
println(p3)
println(p4)
}
data class Employee(val name: String, val age: Int) {}
data class Worker(val name: String = "Unknown", val age: Int = 1970) {}
類的縱向組合
嵌套類Nested Class
內(nèi)部類Inner Class
匿名內(nèi)部類Inner Class
聲明類
類修飾符
構(gòu)造函數(shù)
主構(gòu)造函數(shù)
次構(gòu)造函數(shù)
類的屬性(數(shù)據(jù)結(jié)構(gòu))
類的行為(算法函數(shù))
7.2.2 接口與抽象類
接口的默認實現(xiàn)
interface A {
fun foo() { println("A") } // 默認實現(xiàn), 打印"A"
fun bar()
}
interface B {
fun foo() { println("B") }
fun bar() { println("bar") }
}
// 多繼承時寓辱,顯式指定 super<A>.foo() 以去沖突
class D : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
override fun bar() {
super.bar()
}
}
考慮下面的一個簡單的進行貨幣轉(zhuǎn)換的接口艘绍。該接口的實現(xiàn)方式可能是調(diào)用第三方提供的服務來完成實際的轉(zhuǎn)換操作。
public interface CurrencyConverter {
BigDecimal convert(Currency from, Currency to, BigDecimal amount);
}
該接口在開發(fā)出來之后讶舰,在應用中得到了使用鞍盗。在后續(xù)的版本更新中,第三方服務提供了新的批量處理的功能跳昼,允許在一次請求中同時轉(zhuǎn)換多個數(shù)值般甲。最直接的做法是在原有的接口中添加一個新的方法來支持批量處理,不過這樣會造成已有的代碼無法運行鹅颊。而默認方法則可以很好的解決這個問題敷存。使用默認方法的新接口如下所示。
public interface CurrencyConverter {
BigDecimal convert(Currency from, Currency to, BigDecimal amount);
default List convert(Currency from, Currency to, List amounts) {
List result = new ArrayList();
for (BigDecimal amount : amounts) {
result.add(convert(from, to, amount));
}
return result;
}
}
新添加的方法使用default關鍵詞來修飾堪伍,并可以有自己的方法體锚烦。
目的
接口的默認方法的主要目標之一是解決接口的演化問題。當往一個接口中添加新的方法時帝雇,可以提供該方法的默認實現(xiàn)涮俄。對于已有的接口使用者來說,代碼可以繼續(xù)運行尸闸。新的代碼則可以使用該方法彻亲,也可以覆寫默認的實現(xiàn)。
實現(xiàn)行為的多繼承
7.2.3 繼承
open類
7.2.4 實現(xiàn)接口
7.2.5 函數(shù)重載
override重寫覆蓋父類函數(shù)
7.3 類的實例對象
新建對象
對象屬性(數(shù)據(jù)結(jié)構(gòu))
對象行為(算法函數(shù))
7.4 委托
類的委托
屬性的委托
8 函數(shù)式編程(FP)
8.1 函數(shù)式編程概述
面向?qū)ο缶幊蘋OP特征
函數(shù)式編程FP特征
8.2 Kotlin函數(shù)式編程
8.2.1 函數(shù)是什么
內(nèi)聯(lián)函數(shù)
8.2.2 函數(shù)指針
8.2.3 復合函數(shù)(高階函數(shù))
8.2.4 閉包(closure)
js閉包
function closureExample(objID, text, timedelay) {
setTimeout(function() {
document.getElementById(objID).innerHTML = text;
}, timedelay);
}
closureExample(‘myDiv’, ‘Closure is created’, 500);
groovy閉包
Kotlin閉包
val test = if (5 > 3) {
print("yes")
} else {
print("no")
}
fun tryClosures() {
val values = listOf<Int>(2, 4, 6, 8, 10)
var result = 0
values.forEach {
result += it
}
println("Result: $result")
}
函數(shù)吮廉、Lambda苞尝、if語句、for宦芦、when宙址,都可以稱之為閉包
自執(zhí)行閉包
自執(zhí)行閉包就是在定義閉包的同時直接執(zhí)行閉包,一般用于初始化上下文環(huán)境调卑。 例如:
{ x: Int, y: Int ->
println("${x + y}")
}(1, 3)
節(jié)制的自由
使用閉包寫代碼相當靈活自由抡砂,省略了很多的臨時變量和參數(shù)聲明大咱。 然而,也正是因為閉包的靈活性注益,造成如果泛濫的話徽级,可能會寫出可讀性非常差的代碼。
8.2.5 Lambda表達式(匿名函數(shù))
Lambda 表達式俗稱匿名函數(shù)聊浅,熟悉Java的大家應該也明白這是個什么概念。Kotlin 的 Lambda表達式更“純粹”一點现使, 因為它是真正把Lambda抽象為了一種類型低匙,而 Java 8 的 Lambda 只是單方法匿名接口實現(xiàn)的語法糖罷了。
val printMsg = { msg: String ->
println(msg)
}
fun main(args: Array<String>) {
printMsg.invoke("hello")
}
以上是 Lambda 表達式最簡單的實例碳锈。
首先聲明了一個名為 printMsg 的 Lambda顽冶,它接受一個 String 類型的值作為參數(shù),然后在 main 函數(shù)中調(diào)用它售碳。如果還想省略强重,你還可以在調(diào)用時直接省略invoke,像函數(shù)一樣使用贸人。
fun main(args: Array<String>) {
printMsg("hello")
}
Lambda 表達式作為高階函數(shù)的參數(shù)傳遞
fun main(args: Array<String>) {
log("world", printMsg)
}
val printMsg = { str: String ->
println(str)
}
val log = { str: String, printLog: (String) -> Unit ->
printLog(str)
}
這個例子中间景,log 是一個接受一個 String 和一個以 String 為參數(shù)并返回 Unit 的 Lambda 表達式為參數(shù)的 Lambda 表達式。
8.2.6 內(nèi)聯(lián)函數(shù)(inline)
使用 高階函數(shù) 在運行時會帶來一些不利: 每個函數(shù)都是一個對象, 而且它還要捕獲一個閉包, 也就是, 在函 數(shù)體內(nèi)部訪問的那些外層變量. 內(nèi)存占用(函數(shù)對象和類都會占用內(nèi)存) 以及虛方法調(diào)用都會帶來運行時的消耗.
但是也不是說所有的函數(shù)都要內(nèi)聯(lián)艺智,因為一旦添加了 inline 修飾倘要,在編譯階段,編譯器將會把函數(shù)拆分十拣,插入到調(diào)用出封拧。如果一個 inline 函數(shù)是很大的,那他會大幅增加調(diào)用它的那個函數(shù)的體積夭问。
infix fun Double.powerPI(x: Int): Double {
return Math.pow(this, x + Math.PI)
}
fun infixExample() {
val array = arrayOf(2.0, 4.0, 6.0, 8.0, 10.0)
for (value in array) {
val result = value powerPI 5
println("Result: [ result ]")
}
}
8.2.7 本地函數(shù)(Local Functions)
fun worker() {
fun doWork(work: String) {
println("Working [ $work ]")
}
doWork("Importing user data")
doWork("Processing user data")
doWork("Exporting user data")
}
8.2.8 命名參數(shù)(NamedParameters)
fun addEmployee(name: String, year: Int, address: String) {
}
// Let's call method:
fun namedParametersExaple() {
addEmployee(
name = "John Smith",
year = 1985,
address = "Avenue 666"
)
}
8.2.9 外部函數(shù)external
8.2.10 尾遞歸tailrec
tailrec fun tailRecursiveExample(word: String) {
if (word.length == 1) {
println("--- end")
} else {
println(word)
tailRecursiveExample(word.substring(0..(word.length - 2)))
}
}
fun tryTailRecursiveExample() {
tailRecursiveExample("My word")
}
8.3 函數(shù)式Stream API
8.3.1 filter函數(shù)
8.3.2 map函數(shù)
fun main(args: Array<String>){
val list = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
list.filter { it%2==0 } // 取偶數(shù)
.map{ it*it } // 平方
.sortedDescending() // 降序排序
.take(3) // 取前 3 個
.forEach { println(it) } // 遍歷, 打印
}
8.3.3 forEach
9 Kotlin與Java互操作(Interoperability)
9.1 使用工具互相轉(zhuǎn)換
9.1.1 將 Java 轉(zhuǎn)換為 Kotlin
9.1.2 將 Kotlin 轉(zhuǎn)換為 Java
9.1.3 用 Kotlin 兼容 Java 的做法泽西,本來就是權(quán)宜之計,兼容必然帶來新舊兩種觀念的沖突以及丑陋的發(fā)生
9.2 Kotlin與Java互操作
9.2.1 Kotlin無縫調(diào)用第三方jar庫
9.2.2 執(zhí)行shell
9.2.3 文件操作
9.2.4 多線程代碼
9.3 Kotlin與Java的區(qū)別
9.3.1 void 與 Unit
9.3.2 反射獲取類的 Class
9.3.3 Java 與 Kotlin 關鍵字沖突的處理
9.3.4 static 方法與伴生對象companion object
9.3.5 包級別函數(shù)
9.3.6 重載必須使用override
10 集合類與泛型
10.1 kotlin.collections
10.1.1 不可變集合類
List
// Gives us read only list
fun getList(): List<Int> {
return listOf(1, 3, 5, 7)
}
// Gives us read only map
fun getMap(): Map<String, Double> {
return mapOf("EUR" to 123.20, "USD" to 110.34, "CHF" to 111.4)
}
fun printMap(key: String) {
val map = getMap()
if (key in map) println(map[key]) else println("There is no such key $key")
}
Set
Map
fun traverseMapExample(map: Map<String, Int>) {
for ((key, value) in map) println("value")
}
10.1.2 可變集合類
kotlin.collections.MutableCollection<E>
MutableList<E>
MutableSet<E>
MutableMap<K, V>
10.2 泛型與類型安全
10.2.1 類型參數(shù)
10.2.2 類型推測
10.2.3 協(xié)變與逆變
10.3 類型上下界
11 輕量級線程:協(xié)程(Coroutines)
11.1 協(xié)程概念
val fibonacci = buildSequence {
yield(1) // first Fibonacci number
var cur = 1
var next = 1
while (true) {
yield(next) // next Fibonacci number
val tmp = cur + next
cur = next
next = tmp
}
}
...
for (i in fibonacci){
println(i)
if(i > 100) break //大于100就停止循環(huán)
}
用看似同步的代碼做著異步的事情
11.2 協(xié)程的基本操作
11.2.1 創(chuàng)建
11.2.2 啟動
11.2.3 暫停
11.2.4 繼續(xù)
11.3 競爭條件
11.4 同步
11.5 實現(xiàn)異步
12 使用Kotlin開發(fā)Web應用
12.1 Kotlin集成Spring Boot開發(fā)Web應用
12.1.1 Spring Boot簡介
12.1.2 Kotlin集成Spring Boot
12.2 Spring 5 對 Kotlin的支持
12.2.1 Functional bean registration with Kotlin
Spring Framework 5.0 introduces a new way to register beans using lambda as an alternative to XML or JavaConfig with @Configuration and @Bean. In a nutshell, it makes it possible to register beans with a Supplier lambda that acts as a FactoryBean.
In Java you will for example write:
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(Foo.class);
context.registerBean(Bar.class, () -> new
Bar(context.getBean(Foo.class))
);
While in Kotlin, reified type parameters allow us to simply write:
val context = GenericApplicationContext {
registerBean<Foo>()
registerBean { Bar(it.getBean<Foo>()) }
}
12.2.2 使用Kotlin的函數(shù)式風格API開發(fā) Web應用
Spring Framework 5.0 comes with a Kotlin routing DSL that allows you to leverage the Spring Functional Web API recently announced with clean and idiomatic Kotlin code:
{
("/blog" and accept(TEXT_HTML)).route {
GET("/", this@BlogController::findAllView)
GET("/{slug}", this@BlogController::findOneView)
}
("/api/blog" and accept(APPLICATION_JSON)).route {
GET("/", this@BlogController::findAll)
GET("/{id}", this@BlogController::findOne)
}
}
https://github.com/EasyKotlin/mixit
12.2.3 Kotlin Script based templates
ScriptTemplateView to render templates
This could allow you to write this kind of templates with full autocompletion and refactoring support in your IDE:
import io.spring.demo.*
"""
{i18n("title")}</h1>
<ul>
{i18n("user")} {it.lastname}</li>" }}
</ul>
${include("footer")}
"""
https://github.com/EasyKotlin/kotlin-script-templating
12.3 使用Kotlin的Web框架Ktor開發(fā)Web應用
Ktor is a framework for quickly creating web applications in Kotlin with minimal effort.
import org.jetbrains.ktor.netty.*
import org.jetbrains.ktor.routing.*
import org.jetbrains.ktor.application.*
import org.jetbrains.ktor.host.*
import org.jetbrains.ktor.http.*
import org.jetbrains.ktor.response.*
fun main(args: Array<String>) {
embeddedServer(Netty, 8080) {
routing {
get("/") {
call.respondText("Hello, world!", ContentType.Text.Html)
}
}
}.start(wait = true)
}
https://github.com/Kotlin/ktor/wiki
12.4 基于Kotlin Script的模板引擎
13 使用Kotlin實現(xiàn)DSL
13.1 DSL
13.2 Groovy的DSL語法
13.3 Kotlin使用閉包構(gòu)建 DSL
14使用Kotlin開 發(fā)JavaScript代碼
14.1 Kotlin代碼編譯成js過程
14.2 使用Kotlin開發(fā)JavaScript代碼
15 使用Kotlin開發(fā)Android程序
https://github.com/Kotlin/anko
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
MyActivityUI().setContentView(this)
}
}
class MyActivityUI : AnkoComponent<MyActivity> {
override fun createView(ui: AnkoContext<MyActivity>) = ui.apply {
verticalLayout {
editText()
button("Say Hello") {
onClick { ctx.toast("Hello!") }
}
}
}.view
}
16 使用Kotlin Native開發(fā)原生應用
17 KOTLIN語言生態(tài)
17.1 測試(Testing)
17.2 依賴注入(Dependency Injection)
17.3 JSON序列化(JSON serialization)
17.4 Web 框架
17.5 數(shù)據(jù)庫訪問(Database access)
17.6 工具類(Utilities)
17.7 桌面編程(Desktop programming)
17.8 Http庫
Fuel: https://github.com/EasyKotlin/Fuel
//an extension over string (support GET, PUT, POST, DELETE with httpGet(), httpPut(), httpPost(), httpDelete())
"http://httpbin.org/get".httpGet().responseString { request, response, result ->
//do something with response
when (result) {
is Result.Failure -> {
error = result.getAs()
}
is Result.Success -> {
data = result.getAs()
}
}
}
//if we set baseURL beforehand, simply use relativePath
FuelManager.instance.basePath = "http://httpbin.org"
"/get".httpGet().responseString { request, response, result ->
//make a GET to http://httpbin.org/get and do something with response
val (data, error) = result
if (error != null) {
//do something when success
} else {
//error handling
}
}
//if you prefer this a little longer way, you can always do
//get
Fuel.get("http://httpbin.org/get").responseString { request, response, result ->
//do something with response
result.fold({ d ->
//do something with data
}, { err ->
//do something with error
})
}
val (request, response, result) = "http://httpbin.org/get".httpGet().responseString() // result is Result<String, FuelError>
17.9 并發(fā)庫kotlinx.coroutines
kotlinx.coroutines:https://github.com/EasyKotlin/kotlinx.coroutines
https://github.com/EasyKotlin/kotlinx.coroutines/blob/master/coroutines-guide.md
fun main(args: Array<String>) {
launch(CommonPool) { // create new coroutine in common thread pool
delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
println("World!") // print after delay
}
println("Hello,") // main function continues while coroutine is delayed
Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}
Run this code:
Hello,
World!
18 附錄 參考資料
https://github.com/EasyKotlin/kotlin-in-action
Awesome Kotlin: https://kotlin.link/
Kotlin項目Github源碼:https://github.com/JetBrains/kotlin
Kotlin語言規(guī)范:http://jetbrains.github.io/kotlin-spec/
在線體驗學習Kotlin語言:https://try.kotlinlang.org
官網(wǎng)文檔:http://kotlinlang.org/docs/
https://github.com/trending?l=kotlin
https://github.com/EasyKotlin/Kotlin-for-Android-Developers
https://github.com/EasyKotlin/Bandhook-Kotlin
https://spring.io/blog/2017/01/04/introducing-kotlin-support-in-spring-framework-5-0
xtend: http://www.eclipse.org/xtend/documentation/index.html
Kotlin 開發(fā)者社區(qū)
國內(nèi)第一Kotlin 開發(fā)者社區(qū)公眾號缰趋,主要分享捧杉、交流 Kotlin 編程語言、Spring Boot埠胖、Android糠溜、React.js/Node.js、函數(shù)式編程直撤、編程思想等相關主題非竿。