1. Kotlin介绍
- 基于JVM。可以与Java进行混合开发和相互调用。
- 由JetBrains开发。系出名门,也得到其IDE的良好支持。
- Android官方支持开发语言。
- 更简洁,拥有各种语法糖。
- 更安全,对空安全等进行了优化处理。
2. Kotlin环境
# 项目build.gradle
buildscript {
ext.kotlin_version = '1.1.4-3'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
# 模块build.gradle
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
}
3. kotlin-android-extensions
和ButterKnife说再见
- 当然不用findViewById
- 也不用定义空间变量
- 甚至不用ButterKnife.bind
<Button
android:id="@+id/close_button"
android:text="关闭"
android:layout_alignParentEnd="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
import kotlinx.android.synthetic.main.main_activity.view.*
class MyActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
setContentView(R.layout.main_activity)
close_button.setOnClickListener { mPresenter?.exit() }
}
}
4. Anko
- Anko Commons: 一个轻量级的Helper用于处理 intents, toast, dialogs, logging等等;
- Anko Layouts: 一种可轻量级,可快速开发的动态Android layouts。用代码写layout而不是xml;
- Anko SQLite: a query DSL and parser collection for Android SQLite;
- Anko Coroutines: utilities based on the kotlinx.coroutines library.
以Anko Layouts和Anko Commons举例
在onCreate中使用以下代码可以同时实现layout和setContentView
verticalLayout {
val name = editText()
button("Say Hello") {
onClick { toast("Hello, ${name.text}!") }
}
}
5. 数据类型与等式
首先,Kotlin没有基本数据类型,所有变量包括所谓的基本数据类型在内,都是对象。
其次,Kotlin中有两种相等:
- 参照相等:指向同一个对象 使用 === !==判断
- 结构相等:使用== !=判断,相当于 a?.equals(b) ?: b === null 可见
装箱:可空标识(比如说 Int?) 或者涉及泛型,数值都会被装箱。装箱过的数值已经不保留先前的引用关系
val a: Int = 10000
print (a === a ) //打印 'true'
val boxedA: Int? =a
val anotherBoxedA: Int? = a
print (boxedA === anotherBoxedA ) //注意这里打印的是 'false'
print (boxedA == anotherBoxedA) // Prints 'true'
6. collection 和 字符串
kotlin-stdlib / kotlin.collections
- Array:用于取代Java的数组。
- List:用于取代Java的List
- Map: 用于取代Java的Map
// 通过指定Array大小并提供一个迭代器
// 创建一个 Array<String> 内容为 ["0", "1", "4", "9", "16"]
val asc = Array(5, {i -> (i * i).toString() })
val nullArray : Array<Int?> = arrayOfNulls(3) // 创建一个指定大小的空Array
val list = listOf("a", "b", "c")
val x: IntArray = intArrayOf(1, 2, 3)
val map = mapOf("a" to 1, "b" to 2, "c" to 3)
Kotlin 有专门的类来表示原始类型从而避免过度装箱: ByteArray, ShortArray, IntArray 等等。这些类与 Array 没有继承关系,但它们有一样的方法与属性。
String
// 包含转义符的字符串
val s = "Hello World!\n"
// 不包含转义符的字符串,但不能包含3个及以上的"
val text = """
for (c in "foo")
print(c)
"""
// 模板
val s = "abc"
val str = "$s.length is ${s.length}" //识别为 "abc.length is 3"
8. Ranges
- 范围主要用于 if in (范围) 和 for in (级数) 中使用,判断变量是否处于某个范围或遍历某个范围
- 使用 .. 操作符来或者一些特有操作符来定义
// if in
if (i in 1..10) println(i)
if (x !in 1.0..3.0) println(x)
if (str in "island".."isle") println(str)
// for in
for (i in 1..4) print(i) // prints "1234"
for (i in 4..1) print(i) // prints nothing
for (x in 1.0..2.0) print("$x ") // prints "1.0 2.0 "
for (str in "island".."isle") println(str) // error: string range cannot be iterated over
// 特有操作符
// rangeTo
// 与 .. 相同
// downTo
for (i in 4 downTo 1) print(i)
// step 必须大于0
for (i in 1.0..2.0 step 0.3) print("$i ") // prints "1.0 1.3 1.6 1.9 "
// reversed
for (i in (1..4).reversed()) print(i) // prints "4321"
范围和技术主要通过以下两个接口实现
interface Range<T : Comparable<T>> {
val start: T
val end: T
fun contains(Element : T): Boolean
}
interface Progression<N : Number> : Iterable<N> {
val start : N
val end : N
val increment : Number
}
// if increment > 0
for (int i = start; i <= end; i += increment) {
// ...
}
// if increment < 0
for (int i = start; i >= end; i += increment) {
// ...
}
9. 空安全和类型转换安全
var a: String ="abc"
a = null //编译错误
var b: String? = "abc"
b = null
val l = b.length() //错误:b 不可为空
val l = if (b != null) b.length() else -1 // 类型经过检查后可以安全饮用
val l = b.length() ?: -1 // = ?: 空安全三元操作符
val name = node.getName() ?: throw IllegalArgumentException("name expected") // Throw return
// 安全调用 避免NullPointerException
b?.length()
val l = b !!.length()
// 不安全转换 有可能抛出ClassCastException
val x: String = y as String
// 安全转换 避免ClassCastException
val aInt: Int? = a as? Int
10. 流程控制
val max = if (a > b){
print("Choose a")
a
}
else{
print("Choose b")
b
}
// 用于代替switch if-else的when
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { //Note the block
print("x is neither 1 nor 2")
}
}
// 当有两个case使用同样方法时
when (x) {
0,1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
// 用表达式作为case
when (x) {
parseInt(s) -> print("s encode x")
else -> print("s does not encode x")
}
// 用范围作为case
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
// 类型检查作为case
val hasPrefix = when (x) {
is String -> x.startsWith("prefix")
else -> false
}
// return 控制打断范围
foo outer() {
foo inner() {
return@outer
}
}
11. 函数
使用中缀符号调用函数 成员函数和扩展函数都适用
//给 Int 定义一个扩展方法
infix fun Int.shl(x: Int): Int {
...
}
1 shl 2 //用中缀注解调用扩展函数,与下一句等效
1.shl(2)
使用默认参数减少重载
可以命名参数,当参数较多时更方便设置参数,可读性更强
fun reformat(str: String, normalizeCase: Boolean = true,upperCaseFirstLetter: Boolean = true,
divideByCamelHumps: Boolean = false,
wordSeparator: Char = ' ') {
...
}
reformat(str, true, true, false, '_')
reformat(str, wordSeparator = '_')
12. 高阶函数与lambda
高阶函数就是可以接受函数作为参数并返回一个函数的函数。
fun lock<T>(lock: Lock, body: () -> T ) : T {
lock.lock()
try {
return body()
}
finally {
lock.unlock()
}
}
// 函数作为参数传入
fun toBeSynchroized() = sharedResource.operation()
val result = lock(lock, ::toBeSynchroized)
// lambda表达式传入
val result = lock(lock, { sharedResource.operation() })
- lambda中,如果参数只有一个,可以不写出来,在函数体中用it来表示
- 如果函数的参数只有一个函数,则括号可以不写,直接写lambda
fun <T, R> List<T>.map(transform: (T) -> R): List<R> {
val result = arrayListOf<R>()
for (item in this)
result.add(transform(item))
return result
}
// 调用
val doubled = ints.map {it -> it * 2}
// 简化
val doubled = ints.map { it * 2 }
此外,字面函数或函数扩展还可以作为属性变量而存在
val sum = {x: Int,y: Int -> x + y}
// 以下为完全写法
val sum: (Int, Int) -> Int = {x, y -> x+y }
// 函数扩展
val sum = fun Int.(other: Int): Int = this + other
// 函数扩展在参数中的声明如下
sum : Int.(other: Int) -> Int
13. 标准库
类似JDK提供的一系列标准库,Kotlin也提供了以下标准库,可供参考
包名 | 信息 |
---|---|
kotlin | 核心函数和类型,在所有支持平台均可用 |
kotlin.browser | 访问并操作浏览器 DOM 的 API |
kotlin.concurrent | 并发编程的函数集合 |
kotlin.dom | 用在 W3C DOM 的函数 |
kotlin.io | 用于文件和流的 IO API |
kotlin.jvm | 专门用于 java 平台的函数和注解 |
kotlin.math | 数学反面的 API |
kotlin.platform | 用于自定义 Kotlin 编译器生成的代码,使其在目标平台上更好的交互 |
kotlin.properties | 实现泛型和泛型属性的标准并帮助函数实现自定义泛型 |
kotlin.reflect | Kotlin reflection 运行时 API |
kotlin.reflect.jvm | 用于 Kotlin reflection 和 java 交互的运行时 API |
kotlin.support | |
kotlin.test | 写测试用例的 API |
kotlin.text | 用于正则表达式和文字的函数 |
kotlin.util | 实用函数 |
14. 尚未谈及
本期文章中还有些尚未提及的知识点,如有兴趣还可以自行查阅
- 动态类型
- 反射
- 注解
- 运算符重载
- 内联函数