为什么使用Kotlin
网上关于kotlin的讨论已经热了一个多月了,究竟怎么看待这门语言在Android开发中的应用前景,我觉得还是要留给时间去验证。“我思故我在”,自己的思考在学习的过程中非常重要,尤其是面对新事物。下面说说我的看法,以它主要的优势入手:
Kotlin是门类型安全语言,但同时保持了类型推测,会自动根据常量或变量的具体数字来推测相关的类型,从而大大避免了Java、C等语言繁琐的类型声明,让代码变得异常简洁明了,看起来很像JavaScript。就好比原来大家用过的“万能充”的充电器,不管你的手机电池是什么尺寸或者品牌,只要你的额定电压与电流在安全范围内,都能实现充满电的需求。这很显然大大提高了编程的效率。
Kotlin基本语法
Kotlin有哪些新式的使用方法和语法呢?英语好的同学可以下载
Kotlin英文文档,英语一般的同学直接看中文版的也可以,
kotlin-中文免费文档下载地址。
下面开始简单介绍:
1、函数的使用
定义函数使用fun关键字,如下代码所示:
fun add(a: Int, b: Int): Int {
return a + b
}
函数add有两个Int型的参数,冒号后跟的是函数的返回值,一条代码语句的末尾不用加分号,当然加上分号也没有问题。
上面的add函数还可以简写成如下形式:
fun add(a: Int, b: Int) = a + b;
没有显式指定函数的返回值,会自动推断函数的返回值。
如果一个函数没有返回值,可以写成如下两种形式:
//没有返回值的函数,显式指定Unit为返回值
fun showAddResult(a: Int, b: Int): Unit {
println(a + b)
}
//没有返回值的函数,省略Unit的写法
fun showAddResult2(a: Int, b: Int) {
println(a + b)
}
2、常量和变量
使用val关键字声明一个常量(只读,不可修改),使用var关键字声明一个变量,下面是具体用法:
fun test() {
//使用val关键字声明一个常量(只读),声明常量时必须初始化
val a: Int = 1 //显式指定常量的类型
val b = 2 //自动推断类型
val c: Int //声明一个不初始化的常量,必须显式指定类型
// b = 3 //常量值不可修改,这句代码会报错
//a = 3 //不可以修改常量的值,此句代码会报错
//使用var关键字声明一个变量,变量的值可以修改
var year: Int = 2016 //显式指定变量的类型
var month = 5 //自动推断变量类型
var day: Int //声明一个不初始化的变量,必须显式指定类型
month = 6 //变量值可以被修改
}
3、注释
Kotlin中的注释和Java中类似,但是唯一不同之处是Kotlin中的注释可以嵌套。如下所示:
fun comments() {
// 注释一行代码
// var s = "hello world"
/*注释一段代码
var a = 8
a++
a--*/
}
4、字符串模板
“${}”是一个变量的占位符,“${xxx}”相当于一个文本的模板,在Kotlin中叫字符串模板,它会直接把xxx插入到文本中。
//main方法是整个程序的入口
fun main(args: Array<String>){
var run = 5
run = 6
print("每天跑${run}公里")
}
上面的代码执行后,在控制台打印如下内容:每天跑6公里
5、条件表达式
常规的条件表达式可以是这么写的:
//常规写法的条件表达式,这里的函数返回值不能省略
fun max(a: Int, b: Int): Int {
if(a > b)
return a
else
return b
}
Kotlin可以简写条件表达式,如下所示:
//简写的条件表达式
fun max2(a: Int, b: Int) = if(a > b) a else b
6、可空类型(nullable)
就是指所有“实体的”类型与空的组合,写法是在源类型后面紧跟一个问号;Int?、String?、Boolean?等,这里的“?”指空值null,表示什么都没有。比如一些会员账号的注册会有必填项和选填项,可空类型就是指这种可选填字段的情况。
var addr : String? = "北京大学"
var sex : Boolean?
函数返回值为可空的例子如下代码:
/*
函数返回值为Int?,表示返回值可为空
当参数为空或者为""时,则返回null,否则使用Java中的字符串转整型的方法
这里也体现了kotlin代码和Java代码无缝集成
*/
fun parseInt(s: String): Int? {
if(s == null || s == "")
return null;
return Integer.parseInt(s);
}
7、类型检查和自动类型转换
Kotlin中使用is运算符来检查数据类型和做类型转换,如下代码所示:
/*
当函数参数为字符串类型时,就返回字符串的长度,否则返回空
*/
fun getStringLength(n: Any): Int? {
if(n is String)
return n.length //这里会自动将n转化为字符串类型
return null
}
上面的代码还可以写成:
/*
当函数参数为字符串类型时,就返回字符串的长度,否则返回空
*/
fun getStringLength(n: Any): Int? {
if(n !is String)
return null
return n.length //这里会自动将n转化为字符串类型
}
8、for循环和while循环
while 和
do...while
同Java并无区别,但是要注意for的使用。
//for循环的测试代码
fun testFor() {
var arr = arrayOf(1, 3, 4, 5, 6)
for(i in arr.indices) { //通过索引循环
println(arr[i])
}
for(num in arr) { //直接使用数组中的对象循环
println(num)
}
}
//while循环的测试代码
fun testWhile() {
var i = 0;
while(i < 10) {
print(" " + i)
i++
}
}
9、条件表达式
if...else 正常使用,不过移除了
switch
用更强大的
when
替代,when子式可以是常量、变量、返回数值的表达式、返回Boolean值的表达式,强大到用来替换
if...else if。
如下代码所示:
fun main(args: Array<String>) {
testCase("hello world")
}
fun testCase(obj: Any) {
when(obj) {
is String -> {
print("this is string")
}
is Int -> {
print("this is integer")
}
//代替if...else if...
else -> {
print("unkown value")
}
}
}
10、ranges的使用
(1)使用in操作符检查一个数是否在某个范围内
/*
判断分数是否大于等于90,小于等于100
*/
fun isGood(score: Int) {
if(score in 90..100) //ranges是闭区间
println("very good")
else
println("not so good")
}
(2)检查索引是否越界
/*
检查index是否在数组arr的索引范围内
*/
fun checkIndex(index: Int, arr: Array<Int>) {
if(index in 0..arr.lastIndex) //arr.lastIndex返回的是数组的最后一位的下标
println("index in bounds")
else
println("index out of bounds")
}
(3)遍历一个范围
for(i in 1..5) {
println(i)
}
也可以通过in运算符遍历一个集合,如下代码:
//in运算符遍历一个字符串数组
fun testStr(arr: Array<String>) {
for(str in arr)
println(str)
}
11、万能的冒号
在Kotlin中冒号
:
用万能来称呼绝不为过。常量变量的类型声明,函数的返回值,类的继承都需要它。
//val表示常量var表示变量声明
val name: String = "tutu"
//省略类型说明
var age = "23"
//fun表示函数
fun getName(): String{
return "tutu"
}
//类继承
class UserList<E>(): ArrayList<E>() {
//...
}
除此之外还有一个特别的地方也需要它,使用Java类的时候。Kotlin最终会还是编译成Java字节码,使用到Java类是必然的,在Kotlin语法如下:
val intent = Intent(this, MainActivity::class.java)
类名
::class.java
没有为什么就这么写,记着就是。
12、我是谁的@
除了冒号另一个重要符号
@
,想必用到内部类和匿名内部类的地方一定很多,再加上支持lambda语法,没有它谁告诉你
this
和
return
指的是哪一个。
class User {
inner class State{
fun getUser(): User{
//返回User
return this@User
}
fun getState(): State{
//返回State
return this@State
}
}
}
13、Java的getter/setter方法
Java的
getter/setter
方法自动转换成属性,对应到Kotlin属性的调用
public class User {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
反之Kotlin的属性自动生成Java的
getter/setter
方法,方便在Java中调用,同样的定义在Kotlin中可以偷懒写成如下格式:
class User {
var name: String? = null
var age: String? = null
}
这样一个Java类在Kotlin中只需这样调用
val user = User()
//赋值
user.name = "tutu"
user.age = "23"
//取值
val name = user.name
val age = user.age
我们的
getter/setter
方法有时不会这么简单,这就需要自定义
getter/setter
了,另起一行设置get()/set(value)方法,实现一个Java中常用的单例,这里只为了展示,单例在Kotlin有更简单的方法实现,只要在 package 级别创建一个 object即可
class User {
companion object {
@Volatile var instance: User? = null
get() {
if (field == null) {
synchronized(User::class.java) {
if (field == null)
field = User()
}
}
return field
}
}
var name: String? = null
var age: String? = null
}
自定义getter/setter
重点在field
,跟我们熟悉所Java的this
指代当前类一样,field
指代当前参数,直接使用参数名instance
代替不会报错但单例就没效果了。
14、. lambda
一开始觉得lambda很高级完全看不懂,其实很简单的就是把接口名、方法名和参数类型省掉不写再加个->
罢了,明白这点了很好理解。
// 无参数无返回值
Thread(Runnable {
sleep(1000)
}).start()
// 单参数不带返回值
view.setOnClickListener { v ->
Log.e("tag", "${v.tag}")
}
// 多参数带返回值
view.setOnKeyListener(View.OnKeyListener { v, keyCode, event ->
Log.e("tag", "keyCode$keyCode, ${event.keyCode}")
if (event.keyCode == KeyEvent.KEYCODE_BACK)
return@OnKeyListener true
false
})