Kotlin学习笔记
1 概述
这篇文章首先会介绍Kotlin的特点,接着介绍Kotlin与Java的语法比较。
2 Kotlin特点
- 一门现代化的编程语言
- 可开发跨平台应用,web,Socket,安卓,js,NativeApp等
- 静态编程语言,性能基本与原声Java相当
- 100%兼容Java(说是兼容但实际上有些坑,可以戳这里看看)
- 简洁:跟Java相比真的是简洁很多,语法糖特别舒服
- 安全:彻底解决写Java基本上都会遇到的著名的NullPointerException问题,结合编译器可以在编译截断发现几乎所有可能存在NPE问题的代码
- 互操作性:基于JVM,可以直接拿现有的Java库用
- 工具友好:和JetBrains的IDE结合简直舒服得不要不要的
- 支持函数式编程:比如Lambda表达式
- 支持协程:协程像是非常轻量级的县城,协程将复杂性放入库来简化异步编程,逻辑可以在协程中顺序表达,底层库负责解决异步性,很重要的一点是协程挂起不会阻塞其他线程。官方一个demo是开启10w个协程:
- 支持扩展函数:类似C#,能够扩展一个类的新功能而无需继承类或者使用装饰者这样的设计模式,Kotlin支持扩展函数和扩展属性
- 泛型:当然Java也支持泛型,但是Kotlin比Java支持得更好
- 不依赖XML
下面进入Kotlin的语法部分。
3 基本语法
- 无
;
结尾 println()
代替System.out.println();
- 输出语句中使用
$变量名
代替Java中的+变量名
,比如println('age:$age')
而不是System.out.println('age:'+age)
- 三引号(三个双引号连在一起)中的字符串不会进行转义
4 变量与常量
var
声明变量val
声明常量- 可以在
var
/val
后面加上类型,比如val a:Int
如上图提示val
不能被赋值,提示改为var
。val
类似与Java中的final
,虽然val
引用自身不可变,但是指向的对象是可以改变的。
val
只能进行唯一一次初始化,如果编译器能确保只有唯一一条初始化语句被执行,可以根据条件进行不同的初始化操作:
val a:Intif (4>3){ a = 9}else{ a = 10}
5 表达式和语句
Java中所有的控制结构都是语句,在Kotlin中除了三大循环(while
,for
,do while
)外,大多数控制结构都是表达式。比如if
是表达式而不是语句。也就是说,if
有值而不像Java里面一样没有值(语句)。例子:
var a = if (3>2) 3 else 2
fun main(){ var a = max(4,9)}fun max(a:Int,b:Int): Int = if(a>b) a else b
6 枚举
使用enum class
而不是Java中的enum
:
fun main(){ val months = Months.May println(months.days)}enum class Months(val days:Int){ May(31), Jun(30)}
7 when
when
相当于Java中的switch
:
fun main(){ val months = Months.May when(months) { Months.May -> print('May') Months.Jun -> print('June') }}enum class Months(val days:Int){ May(31), Jun(30),;}
使用->
进行了简化。
8 循环
8.1 while与do while
与Java一样。
8.2 for
使用..
表示区间,在i
前面没有类型:
for (i in 1..100) print(i)
注意区间是两边都包含的,也就是1..100
表示i
从1循环到100。
使用下标迭代:
val arr = arrayListOf('1111','2222','333')for ((i,e) in arr.withIndex()) println('$i = $e')
输出:
0 = 11111 = 22222 = 333
9 类
9.1 构造方法
class Person(val name:String)
不需要像Java一样this.xxx=xxx
。
9.2 getter/setter
因为val
代表常量,而var
代表变量,setter是用于改变值的,因此,使用var
声明的属性具有getter与setter,使用val
声明的属性只有getter。Kotlin没有提供直接操纵getter与setter的方式,通过使用.属性名
进行修改属性或者获取属性:
class Person{ var name = '' val id = ''}var person = Person()person.name='111'person.id='222' //编译不通过,id为val不可变
9.3 自定义getter/setter
在相应的属性后面加上get
/set
即可自定义getter/setter:
class Person{ var name='' get() { return 'name'+field } var id='' set(id) { field = id }}
在get
/set
中使用field
表示字段,比如在上面例子中的get中,field
表示name
,而在下面的set
中,field
表示自己的id
,=
后面是参数的id
。
10 异常
10.1 抛出异常
直接throw
,无需new
:
val age = 300if(age !in 1..100) throw IllegalArgumentException('Out of range:$age')
10.2 try/catch
try { throw Exception('exception')}catch (e:Exception){ e.printStackTrace()}
10.3 受检异常与不受检异常
Java中的异常有两类:
Unchecked Exception
:不受检异常,可以不进行try/catch
处理,包括Runtime Exception
及其子类Checked Exception
:受检异常,必须进行try/catch
处理或者声明需要抛出,不属于不受检异常的异常都属于受检异常
Kotlin不区分两者,也就是对于Java的受检异常可以不处理,比如:
fun main(){ throw IllegalArgumentException('333')}
可通过编译,而Java中的
public class Test{ public static void main(String []args) { throw new Exception('111'); }}
则无法通过编译。
11 集合类
val arrayList = ArrayList<Int>()arrayList.add(3)arrayList.add(9)arrayList.forEach { t-> println(t) }val hashSet = hashSetOf<String>()hashSet.add('2222')hashSet.add('99999')hashSet.forEach{t-> println(t)}val list = listOf(3,5,5)list.forEach{t-> println(t)}val map = mapOf('a' to 1,'b' to 2)map.forEach{(k,v)-> println('$k to $v')}
可以直接使用集合类或者xxxOf
创建,遍历使用forEach
与Lambda,Kotlin风格的Lambda使用{}
。
12 函数
12.1 基本语法
fun printStr(str:String){ println(str)}fun add(a:Int):Int{ return a+3}
fun
声明函数- 形参类型在形参名称后
- 返回类型放在最后,前面需要带
:
- 函数不强制放在类中
12.2 默认参数
Java里面没有默认参数,实现类似功能需要重载去解决,而Kotlin的函数可以具有默认参数:
fun main(){ println(add()) println(add(1)) println(add(1,2))}fun add(a:Int = 3,b:Int = 4):Int = a+b
可以省略的只有在末尾的参数,也就是默认参数从末尾开始确定默认值。
12.3 命名参数
类似Python,调用函数时使用形参名称与值的方式调用而不是仅仅通过值调用,同时可以结合默认参数省略部分值。
fun main(){ println(add(b=1)) println(add(b=5,a=9))}fun add(a:Int = 3,b:Int = 4):Int = a+b
12.4 可变参数
使用vararg
:
fun main(){ println(add(1,2,3,4))}fun add(vararg a:Int):Int = a.sum()
13 顶层函数与顶层属性
13.1 顶层函数
Kotlin中可以将函数放在代码文件的顶层,不用附属于任何类,但仍然是包内作用域,包外需要import
,作用类似Java中的静态函数。
fun add(vararg a:Int):Int = a.sum()fun main(){ println(add(1,2,3,4))}
Java中调用顶层函数时可以使用默认的Kotlin文件名作为默认包去调用,也可以使用@file:JvmName
修改调用的包名,比如上面的文件名为Test.kt
,则Java中调用的代码如下:
TestKt.add()
使用注解后:
@file:JvmName('Test')fun add(vararg a:Int):Int = a.sumfun main(){ println(add(1,2,3,4))}
Java调用方式改变如下:
Test.add()
13.2 顶层属性
与Java中的静态属性类似,有点像全局变量或全局常量,可以使用var
,val
,const val
修饰:
var a = 0val b = 0const val c = 0fun main(){ println(++a) println('$bn$c') test()}fun test(){ println('$an$bn$c')}
val
与const val
的主要区别是:
val
实质上相当与Java中的private final static
const val
实质上相当于Java中的public final static
const
相当于@JvmField
,也就是说const val a = 0
与@JvmField val a = 0
等价:
14 参考
1、Kotlin语言的特点和优劣势2、Java受检异常与不受检异常3、Kotlin中的getter与setter4、Kotlin与Java的异同5、Kotlin之const val与val