纲要
- 前言
- Kotlin是什么?
- 为什么使用Kotlin?
- Kotlin常用特性有哪些?
- 如何在开发中使用Kotlin?
- 使用Kotlin常见问题有哪些?
前言
从2017年秋季接触Kotlin以来,开始3个月写了一些学习Demo,最近半年才开始用Kotlin开发企业级的APP,遇到了一点坑,但整体感觉:简洁、高效,以至于现在丝毫不想写又臭又长的Java代码。
还在坚持写Java的同学不妨试试Kotlin,一定会让你流连忘返、乐不思Java ,:p。
Kotlin是什么?
简介
Kotlin是一种在Java虚拟机上运行的静态类型编程语言,它也可以被编译成为JavaScript源代码。
主要由JetBrains的圣彼得堡团队所开发,其名称来自于圣彼得堡附近的科特林岛。
静态动态类型编程语言:通俗讲
静态类型指的是编译器在compile time执行类型检查,动态类型指的是编译器(虚拟机)在runtime执行类型检查
应用范围
适用构建Kotlin应用的平台(引自官网)JVM-Java服务端开发(替代Java?)
Android
Browser-JavaScript开发(替代JavaScript?)
Native-C相关开发(替代C、Object-C和Swift?)
历史
- 2011年7月-JetBrains推出Kotlin项目
- 2016年2月-发布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高级开发者使用Kotlin的人数达到35%
为什么使用Kotlin?
通用理由
参考示例见官方
https://www.kotlincn.net/
使用Kotlin开发Android的理由
- 兼容性:Kotlin 与 JDK 6 完全兼容,保障了 Kotlin 应用程序可以在较旧的 Android 设备上运行而无任何问题。Kotlin 工具在 Android Studio 中会完全支持,并且兼容 Android 构建系统。
- 性能:由于非常相似的字节码结构,Kotlin 应用程序的运行速度与 Java 类似。 随着 Kotlin 对内联函数的支持,使用 lambda 表达式的代码通常比用 Java 写的代码运行得更快。
- 互操作性:Kotlin 可与 Java 进行 100% 的互操作,允许在 Kotlin 应用程序中使用所有现有的 Android 库 。这包括注解处理,所以数据绑定和 Dagger 也是一样。
- 占用:Kotlin 具有非常紧凑的运行时库,可以通过使用 ProGuard 进一步减少。 在实际应用程序中,Kotlin 运行时只增加几百个方法以及 .apk 文件不到 100K 大小。
- 编译时长:Kotlin 支持高效的增量编译,所以对于清理构建会有额外的开销,增量构建通常与 Java 一样快或者更快。
- 学习曲线:对于 Java 开发人员,Kotlin 入门很容易。包含在 Kotlin 插件中的自动 Java 到 Kotlin 的转换器有助于迈出第一步。Kotlin 心印 通过一系列互动练习提供了语言主要功能的指南。
另外的理由
- 不用写烦人的findViewById
- Android Studio支持Java To Kotlin一键转换
Kotlin常用特性有哪些?
具体语法可见Kotlin官网,或对应的中文版
以下主要说一下常用的语法或特性
基本语法
定义变量
fun testDefination() {
// 不可变
val a: Int = 1 // 立即赋值
val b = 2 // 自动推断出 `Int` 类型
val c: Int // 如果没有初始值类型不能省略
c = 3 // 明确赋值
// 可变
var x = 5 // 自动推断出 `Int` 类型
x += 1
}
class KotlinSyntax {
data class Person(val name: String, val age: Int, val isMale: Boolean,
var address: String? = "")
// 懒加载
private val freshman by lazy {
Person("feifei", 18, true)
}
// 延迟加载。定义成员变量时必须初始化,但不想初始化或不想引入空时,可以使用延迟加载
private lateinit var old: Person
}
字符串模板
@Test fun testStringTemplates() {
val age = 12
val name = "feifei"
print("name -> $name, age -> $age")
}
Elvis 操作符?
// 判空。如果str=null,会打印:Length = null
@Test fun testNull (str: String?) {
println("Length = " + str?.length)
}
// 类型转换
@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"
}
循环表达式和集合
@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` 在该条件分支内自动转换成 `String`
return obj.length
}
// 在离开类型检测分支后,`obj` 仍然是 `Any` 类型
return null
}
默认参数
@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)
}
数据模型
// 会为 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
}
方法作为其他方法的参数
一般用于回调
// 场景,有一个轮播条,点击其中一个进入详情
// 定义一个adapter,传入值和对调函数
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)
// 设置点击监听
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
}
范围外 run,let,with,apply
class Turtle {
fun penDown(){}
fun penUp(){}
fun turn(degrees: Double){}
fun forward(pixels: Double){}
}
// 对一个对象实例调用多个方法 (with)
@Test
fun testWith() {
val myTurtle = Turtle()
with(myTurtle) { // 画一个 100 像素的正方形
penDown()
for(i in 1..4) {
forward(100.0)
turn(90.0)
}
penUp()
}
}
Java调用Kotlin
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开发的工具
- Kotlin Android 扩展是一个编译器扩展, 可以让你摆脱代码中的
findViewById()
调用,并将其替换为合成的编译器生成的属性。- Anko 是一个提供围绕 Android API 的 Kotlin 友好的包装器的库 ,以及一个可以用 Kotlin 代码替换布局 .xml 文件的 DSL。
如何在开发中使用Kotlin
非Android开发
Android开发
创建新项目
Android Studio 3.0+完全支持kotlin,创建项目的时候,默认勾选支持Kotlin,创建完项目后会自动在gradle文件中引入插件和扩展插件。
创建完工程后,工程gradle文件中
工程gradle文件
应用Module gradle文件中
应用Module gradle文件
Java 转 Kotlin
- 切到要转换的Java文件
- Android Studio菜单 Code -> ‘Convert Java File to Kotlin File’, 或 Mac环境下,双击Shite键,输入 covert java....出现‘Convert Java File to Kotlin File’选项。
Java转kotlin的常见问题
一般而言可以直接转换,无需修改,但有时需要手动修改,一般在如下几个地方出现:
-
逻辑操作符。kotlin中只有Int类型的值才能直接进行逻辑运算,其他类型如Byte要转为Int之后才能进行逻辑运算。且,kotlin中的逻辑运算是作为方法出现的。
逻辑运算 Java vs Kotlin
-
单行赋值后进行比较
这个在读流操作时经常出现
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);
}
}
直接转换成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常见问题有哪些?
待续
网友评论