《Kotin 编程思想·实战》

《Kotin 编程思想·实战》


《Kotlin极简教程》正式上架:

点击这里 > 去京东商城购买阅读

点击这里 > 去天猫商城购买阅读


1 JVM语言家族概览

1.1 编程语言简史

1.2 程序执行的三种方式

1.2.1 编译执行

1.2.2 解释执行

1.2.3 虚拟机执行

1.3 JVM概述

1.3.1 Java源代码编译执行过程

1.3.2 Java Class文件简介

1.3.3 JVM字节码执行过程

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。

静态类型

特点

扩展方法 :加强封闭类型的新功能。

Lambda表达式:匿名函数文字简洁的语法。

将lambda表达式编译成匿名内部类。

运算符重载:让库更表达。

强大的交换机的表达:类型与隐式类型转换开关。

多个调度:即多态方法调用。

模板表达式:智能空间处理。

报表:一切都是表达式。

属性:访问和定义getter和setter方法的速记法。

局部类型推理:很少需要写下类型签名了。

全面支持Java的泛型:包括所有的一致性和转换规则。

类型系统:Xtend的静态类型是不错的,因为它允许更好的静态分析和基于类型信息的更好的工具。然而,缺点是额外的复杂性

2 Kotlin简介

2.1 kotlin简史

2.2 快速学习工具

2.2.1 云端IDE

2.2.2 本地命令行环境搭建

2.2.3 Kotlin REPL

2.2.4 使用IntelliJ IDEA

2.2.5 使用Gradle构建工程

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执行原理分析

4.2 kotlin代码执行过程

4.3 Kt.class与Java.class区别

5 语言基础

5.1 基础语法

5.1.1 包(package)

package打包与import导包

源文件可以不需要匹配目录和包,源文件可以放在任何文件目录

如果没有任何包声明的话,则当中的代码都属于默认包,导入时包名即为函数名! 比如: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表达式

判断结构(条件表达式)

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 循环

while循环

for循环

Kotlin中的while与do-while,break,continue与Java中的类似,不过Kotlin中多了个好玩的东西: Ranages,包含与范围有关的函数操作符

Ranages

在范围内与不在范围内

fun main(array: Array<String>) { for ((index, value) in array.withIndex()) { println("[ $index ][ $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()

你也可以调lastIndex来获得最后的下标,写成if(i in 0..array.lastIndex) 如果你不想顺着遍历,想反过来遍历,可以利用downTo (递减)关键字,从最大值到最小值递减! for(i in 9 downTo 5) print(arr[i]) println() 可能你还想隔着遍历,比如只遍历:10,7,4,1,可以用 step (步长)关键字!后面跟着的是步长, 比如你可以写成小数0.1这样也行,示例: for(i in 9 downTo 3 step 3) print(arr[i])

倒序遍历

5.1.7 代码注释

5.1.8 异常

Kotlin中所有的Exception都继承了Throwable,含有一个message且未经检查。 这表示不会强迫我们在任何地方使用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 修饰符

访问权限

public:默认,总是可见

internal:同模块可见

private:声明范围与同模块的子作用域可见

protected:类似于private,但对子类也可见

5.2.2 关键保留字

var:定义变量

val:定义常量

fun:定义方法

Unit:默认方法返回值,类似于Java中的void,可以理解成返回没什么用的值

vararg:可变参数

如果是可变参数的话,可以使用 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:递减,循环时可用,每次减1

step:步长,循环时可用,设置每次循环的增加或减少的量

when:Kotlin中增强版的switch,可以匹配值,范围,类型与参数

is:判断类型用,类似于Java中的instanceof()

5.2.3 运算符

5.2.4 赋值符

5.3 函数

5.3.1 main函数

5.3.2 定义函数

使用 fun 关键字来声明

如果没有访问控制符修饰的fun默认是public final的!

返回值:Unit

扩展函数

直接定义在文件中,而不需要依赖于任何的类的函数

成员函数

写在class或object中的函数

5.3.3 包级函数

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()

函数式接口(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 匿名函数

// new 一个线程 // 匿名类写法 val runnable1 = object : Runnable{ override fun run() { println("I'm an anonymous class") } }

// 函数写法, 略像js val runnable2 = fun (){ println("I'm a function") }

5.4 特色功能

5.4.1 函数拓展和属性拓展(Extensions)

fun main(args: Array<String>) { val list = listOf("1", "2", "3", "4")

// 函数拓展
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 // 返回计算结果 }

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实现原理简析

空类型强转为非空类型

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 类型系统

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: 字符串类型

字符串常量

字符串函数

字符串模板

转义字符串

Kotlin居然没有自动转型

for(i in 0..arr.lastIndex) print(arr[i] + " ") 不能自动转型,这样写代码多麻烦

for(i in 0..arr.lastIndex) print(arr[i].toString() + " ")

6.3.5 Array: 数组类型

原生数组类型

创建数组

定长数组:val fixedSizeArray = arrayOfNulls<Int>(10) 空数组: 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])

访问数组

使用[]

[]访问数组元素在这里实际上是进行了操作符的 重载,调用的其实是Array类的getter和setter方法,但是编译成字节码的时候会进行优化, 变成直接访问数组的内存地址,所以并不会造成性能损失!

遍历数组

foreach遍历

for(e in arr) println(e)

根据下标遍历

for(i in arr.indices) println(arr[i])

indices代表下标!范围:(0 <= indices < 数组size)

6.4 特殊类型

kotlin.Any

kotlin.Nothing

kotlin.Unit

kotlin.KClass<T>

6.5 可空类型(Nullable Types)

6.6 函数类型( Functional Types)

闭包类型

6.7 类型检测

is运算符

as运算符

6.8 类型转换

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 面向对象编程(OOP)

7.1 面向对象思想

7.2 类与继承

7.2.1 类

类的横向分类

抽象类

接口类

枚举类

注解类

静态类与伴生对象

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.race}" is SuperEnum.Animal -> "${superEnum.specie} with ${superEnum.legsCount} legs." is SuperEnum.Bacteria -> "Some micro organism ..." }

data 数据类

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

内部类Inner Class

匿名内部类Inner Class

声明类

类修饰符

构造函数

主构造函数

次构造函数

类的属性(数据结构)

类的行为(算法函数)

7.2.2 接口与抽象类

接口的默认实现

interface A { fun foo() { println("A") } // 默认实现, 打印"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()
}

}

考虑下面的一个简单的进行货币转换的接口。该接口的实现方式可能是调用第三方提供的服务来完成实际的转换操作。

public interface CurrencyConverter { BigDecimal convert(Currency from, Currency to, BigDecimal amount); } 该接口在开发出来之后,在应用中得到了使用。在后续的版本更新中,第三方服务提供了新的批量处理的功能,允许在一次请求中同时转换多个数值。最直接的做法是在原有的接口中添加一个新的方法来支持批量处理,不过这样会造成已有的代码无法运行。而默认方法则可以很好的解决这个问题。使用默认方法的新接口如下所示。

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关键词来修饰,并可以有自己的方法体。

目的

接口的默认方法的主要目标之一是解决接口的演化问题。当往一个接口中添加新的方法时,可以提供该方法的默认实现。对于已有的接口使用者来说,代码可以继续运行。新的代码则可以使用该方法,也可以覆写默认的实现。

实现行为的多继承

7.2.3 继承

open类

7.2.4 实现接口

7.2.5 函数重载

override重写覆盖父类函数

7.3 类的实例对象

新建对象

对象属性(数据结构)

对象行为(算法函数)

7.4 委托

类的委托

属性的委托

8 函数式编程(FP)

8.1 函数式编程概述

面向对象编程OOP特征

函数式编程FP特征

8.2 Kotlin函数式编程

8.2.1 函数是什么

内联函数

8.2.2 函数指针

8.2.3 复合函数(高阶函数)

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")

}

函数、Lambda、if语句、for、when,都可以称之为闭包

自执行闭包

自执行闭包就是在定义闭包的同时直接执行闭包,一般用于初始化上下文环境。 例如:

{ x: Int, y: Int -> println("${x + y}") }(1, 3)

节制的自由

使用闭包写代码相当灵活自由,省略了很多的临时变量和参数声明。 然而,也正是因为闭包的灵活性,造成如果泛滥的话,可能会写出可读性非常差的代码。

8.2.5 Lambda表达式(匿名函数)

Lambda 表达式俗称匿名函数,熟悉Java的大家应该也明白这是个什么概念。Kotlin 的 Lambda表达式更“纯粹”一点, 因为它是真正把Lambda抽象为了一种类型,而 Java 8 的 Lambda 只是单方法匿名接口实现的语法糖罢了。

val printMsg = { msg: String -> println(msg) }

fun main(args: Array<String>) { printMsg.invoke("hello") } 以上是 Lambda 表达式最简单的实例。

首先声明了一个名为 printMsg 的 Lambda,它接受一个 String 类型的值作为参数,然后在 main 函数中调用它。如果还想省略,你还可以在调用时直接省略invoke,像函数一样使用。

fun main(args: Array<String>) { printMsg("hello") }

Lambda 表达式作为高阶函数的参数传递

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 为参数并返回 Unit 的 Lambda 表达式为参数的 Lambda 表达式。

8.2.6 内联函数(inline)

使用 高阶函数 在运行时会带来一些不利: 每个函数都是一个对象, 而且它还要捕获一个闭包, 也就是, 在函 数体内部访问的那些外层变量. 内存占用(函数对象和类都会占用内存) 以及虚方法调用都会带来运行时的消耗.

但是也不是说所有的函数都要内联,因为一旦添加了 inline 修饰,在编译阶段,编译器将会把函数拆分,插入到调用出。如果一个 inline 函数是很大的,那他会大幅增加调用它的那个函数的体积。

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: [ $value ][ $result ]") } }

8.2.7 本地函数(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 命名参数(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 外部函数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 函数式Stream API

8.3.1 filter函数

8.3.2 map函数

fun main(args: Array<String>){ val list = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) list.filter { it%2==0 } // 取偶数 .map{ it*it } // 平方 .sortedDescending() // 降序排序 .take(3) // 取前 3 个 .forEach { println(it) } // 遍历, 打印 }

8.3.3 forEach

9 Kotlin与Java互操作(Interoperability)

9.1 使用工具互相转换

9.1.1 将 Java 转换为 Kotlin

9.1.2 将 Kotlin 转换为 Java

9.1.3 用 Kotlin 兼容 Java 的做法,本来就是权宜之计,兼容必然带来新旧两种观念的冲突以及丑陋的发生

9.2 Kotlin与Java互操作

9.2.1 Kotlin无缝调用第三方jar库

9.2.2 执行shell

9.2.3 文件操作

9.2.4 多线程代码

9.3 Kotlin与Java的区别

9.3.1 void 与 Unit

9.3.2 反射获取类的 Class

9.3.3 Java 与 Kotlin 关键字冲突的处理

9.3.4 static 方法与伴生对象companion object

9.3.5 包级别函数

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("$key : $value") }

10.1.2 可变集合类

kotlin.collections.MutableCollection<E>

MutableList<E>

MutableSet<E>

MutableMap<K, V>

10.2 泛型与类型安全

10.2.1 类型参数

10.2.2 类型推测

10.2.3 协变与逆变

10.3 类型上下界

11 轻量级线程:协程(Coroutines)

11.1 协程概念

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就停止循环 }

用看似同步的代码做着异步的事情

11.2 协程的基本操作

11.2.1 创建

11.2.2 启动

11.2.3 暂停

11.2.4 继续

11.3 竞争条件

11.4 同步

11.5 实现异步

12 使用Kotlin开发Web应用

12.1 Kotlin集成Spring Boot开发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的函数式风格API开发 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.*

""" ${include("header")} <h1>${i18n("title")}</h1> <ul> ${users.joinToLine{ "<li>${i18n("user")} ${it.firstname} ${it.lastname}</li>" }} </ul> ${include("footer")} """

https://github.com/EasyKotlin/kotlin-script-templating

12.3 使用Kotlin的Web框架Ktor开发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实现DSL

13.1 DSL

13.2 Groovy的DSL语法

13.3 Kotlin使用闭包构建 DSL

14使用Kotlin开 发JavaScript代码

14.1 Kotlin代码编译成js过程

14.2 使用Kotlin开发JavaScript代码

15 使用Kotlin开发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开发原生应用

17 KOTLIN语言生态

17.1 测试(Testing)

17.2 依赖注入(Dependency Injection)

17.3 JSON序列化(JSON serialization)

17.4 Web 框架

17.5 数据库访问(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 并发库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语言规范:http://jetbrains.github.io/kotlin-spec/

在线体验学习Kotlin语言:https://try.kotlinlang.org

官网文档: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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏开发与安全

算法:静态查找表(Static Search Table)(顺序查找、二分查找、插值查找、斐波纳契查找)

查找表(Search table)是由同一类型的数据元素(或记录)构成的集合。关键字(key)是数据元素中某个数据项的值,又称为键值,用它可以表示一个数据元素,...

2415
来自专栏大内老A

ASP.NET MVC三个重要的描述对象:ControllerDescriptor

ASP.NET MVC应用的请求都是针对某个Controller的某个Action方法,所以对请求的处理最终体现在对目标Action方法的执行。而Action方...

1847
来自专栏写代码的海盗

scala与java之间的那些事

  scala与java之间的关系,我认为可以用一句话来开头:scala来源于java,但又高于java。   scala的设计者Martin Odersky就...

3675
来自专栏积累沉淀

Java IO结构各种流详解

花了两天时间研究了一下Java IO的流,对于各种流,加深了一下理解 首先看我做的思维导图 ? 文件流 public class FileIO { ...

6379
来自专栏我杨某人的青春满是悔恨

深入理解 weak-strong dance

这时handler持有 Block 对象,而 Block 对象虽然捕获了weakSelf,延长了weakSelf这个局部变量的生命周期,但weakSelf是附有...

1014
来自专栏owent

VC和GCC内成员函数指针实现的研究(一)

最近在《C++对象模型》一书里说到的virtual的成员函数指针,低于128的被cfront编译器认为是虚表偏移量(支持子类对父类函数的覆盖)。VC只是提了下单...

973
来自专栏一个会写诗的程序员的博客

Kotlin 中的集合类排序Kotlin 开发者社区

Kotlin使用扩展方法构建在Java Collection框架之上。这大大提高了可用性和可读性,而无需第三方依赖,如Apache Commons或Guava。

1565
来自专栏恰童鞋骚年

.NET基础拾遗(1)类型语法基础和内存管理基础

在.NET中所有的内建类型都继承自System.Object类型。在C#中,不需要显示地定义类型继承自System.Object,编译器将自动地自动地为类型添...

1132
来自专栏Jimoer

在Java的反射中,Class.forName和ClassLoader的区别

最近在面试过程中有被问到,在Java反射中Class.forName()加载类和使用ClassLoader加载类的区别。当时没有想出来后来自己研究了一下就写下来...

1512
来自专栏jessetalks

背后的故事之 - 快乐的Lambda表达式(二)

快乐的Lambda表达式   上一篇 背后的故事之 - 快乐的Lambda表达式(一)我们由浅入深的分析了一下Lambda表达式。知道了它和委托以及普通方法的区...

2784

扫码关注云+社区

领取腾讯云代金券