Kotlin认识与基础语法
1.认识Kotlin
2010年大名鼎鼎的JetBrains公司(知名的InteliJ IDEA就是他们的产品之一),产生创造Kotlin的想法,从那之后开始了Kotlin的语言设计。2017年Google I/O大会之后,Kotlin成为了Android平台上官方支持的语言,被称之为“更好的Java”。
特性
- 与现有的Java代码完全兼容
- 在很大程度上实行了类型推导,Java 10才支持局部变量的推导
- 放弃static关键字,但又引入了object,可以直接使用它声明单例,Java则必须依靠构建所谓的“单例模式”才能等效表达。
- 具有一些“特殊类”,比如Data Classes(数据类),Sealed Classes(密封类),我们可以构建更深程序上的代数数据类型,结合when表达式来使用。
强大的生态
- Android开发 我们不公可以用Kotlin调用现成的Java库,而且还有Google提供的Kotlin扩展库。
- 服务端开发 这是JVM语言最大的一个应用领域,自然也是Kotlin发挥的舞台。在Android支持Kotlin之后,Spring Framework 5也对它敞开了怀抱。基于Kotlin更自然的函数式特性,用Spring进行Web开发会在某些方面比Java有更好的体验。
- 前端开发 Kotlin还有两个强大的特性:dynamic类型及类型安全的构建器。前者实现其与JavaScript互通,后者可以帮助开发者构建可靠的HTML页面。你可以尝试使用Kotlin构建UI。
- 原生环境开发 Kotlin Native离开了JVM,可以直接编译成机器码供系统环境运行。
KMM
Kotlin Multiplatform Mobile,Kotlin基于上述的生态特性,可实现跨平台开发,它注重的是将与平台无关的代码通用化,共用一份Kotlin代码实现,生成多个平台的原生产物;至于平台特性相关的代码(包括UI)建议使用各自平台的原生方案,各自写一份代码解决。
2. 基础语法
- 类型推导
//变量声明
val str:String = "I am kotlin"
//类型推导
val string = "I am kotlin"
val int = 1314
val long = 1314L
val float = 13.14f
val double = 13.14
val doubleLong = 10.1e6
//打印以下的变量类型,如println(string.javaClass.name)
println(string.javaClass.name) //java.lang.String
println(int.javaClass.name) //int
println(long.javaClass.name) //long
println(float.javaClass.name) //float
println(double.javaClass.name) //double
println(doubleLong.javaClass.name) //double
- 声明函数的返回值类型
//声明函数,Unit类型,类似于java中的void关键字,1个int类型参数
fun sum(x:Int):Unit{
val y = x + 1
}
//声明函数,int类型返回值,两个int类型参数
fun sum(x:Int,y:Int):Int {return x + y}
//上述函数的另一种实现,用等号定义一个函数,表达式函数体,与之相对的称之为代码块函数体
fun sum1(x:Int,y:Int):Int = x + y
fun sum2(x:Int,y:Int) = x + y
//在一些类似递归的复杂情况下,即使用表达式定义函数,必须显示声明类型
fun foo(n:Int):Int = if (n == 0) 1 else n * foo(n - 1)
- val与var
//val:引用不可变
//尽可能采用val、不可变对象及纯函数来设计函数
//作为防御性编码思维模式,更安全可靠,因为变量的值永远不会在其他地方被改变(反射技术除外,适合并发编程)
val x = intArrayOf(1,2,3)
//x = intArrayOf(2,3,4) //Error:Val cannot be reassigned,类似于java的final,只读变量
x[0] = 3 //引用虽然不可更改,值是可以改变的
println(x[0]) //输出3
//var 变量
var y = 5
y += 5
println(y)
var r = cal(listOf(1,2,3))
println(r)
fun cal(list:List<Int>):Int{
//[1,2,3],el为集合中的元素
//res = 0
//res *= el
//res += el
return list.fold(0) {
res,el -> res * el + el
}
}
- 函数类型
fun main(){
val fn = fun04(10)
fn(20)
val fn05 = object : (Int) -> Int{
override fun invoke(p: Int): Int {
return p * 5
}
}
fun05(fn05)
}
//函数类型
fun fun01(x:Int):Int{
//(Int)-> Int
// 1个int类型参数,返回值类型为Int
return x + 5
}
fun fun02(){
//()-> Unit
// 没有参数,返回值类型为Unit
}
fun fun03(x:Int,s:String):Unit{
//(Int,String) -> Unit
//1个int类型参数,1个String类型参数,返回值类型为Unit
}
//(Int)->((Int)->Unit)
//(Int)->Int->Unit
//1个int参数,返回值类型为(Int)->Unit
fun fun04(x:Int):((Int) -> Unit){
return object : (Int) -> Unit{
override fun invoke(p: Int) {
println(x + p)
}
}
}
//((Int)->Int)->Unit
//1个(Int)->Int类型参数,返回值类型为Unit
fun fun05(fn:(Int)->Int):Unit{
val r = fn(10)
println(r)
}
- 方法和成员引用
fun main(){
//方法引用,类的构造方法引用
val getBook = ::Book
//输出Dive into Kotlin
println(getBook("Dive into Kotlin").name)
//成员引用
val bookNames = listOf(Book("Thinking in Java"),Book("Dive int Kotlin")).map(Book::name)
//输出[Thinking in Java, Dive int Kotlin]
println(bookNames)
}
- Lambda
fun main(){
//语法糖Lambda,下面3种是等价的
val sum1 : (Int,Int) -> Int = { x:Int,y:Int -> x + y}
val sum2 = {x:Int,y:Int -> x + y}
val sum3 : (Int,Int) -> Int = { x,y -> x + y}
val foo = { x:Int->
val y = x - 2
y //相当于return y
}
println(foo(10)) //打印输出8
listOf(1,2,3).forEach{ p(it) } //打印输出123
listOf(1,2,3).forEach { it -> p(it) } //等价于上面的代码
listOf(1,2,3).forEach { p(it).invoke() } //invoke方法
}
fun p(int :Int) = {
print(int)
}
//Function类型
//Kotlin在JVM层设计了Function类型(Function0,Function1...Function22)来兼容Java的Lambda表达式
//每个Function类型都有一个invoke方法
interface Function1<in P1,out R> : kotlin.Function<R>{
fun invoke(p1:P1):R
}
- 函数,lambda和闭包
//代码块函数体在返回非Unit类型的值,必须带return
fun sumReturn1(x:Int,y:Int):Int {
return x + y
}
//单表达式函数体,可以省略return
fun sumReturn2(x:Int,y:Int) = x + y
val methodDo1 = { x:Int,y:Int -> x + y} //methodDo1.invoke(1,2)或methodDo1(1,2)
fun methodDo2(x:Int) = {y:Int -> x + y} //methodDo2(1).invoke(2)或methodDo2(1)(2)
fun main(){
//Kotlin的闭包不仅可以访问外部变量,还能修改其值
var sum = 0
listOf(1,2,3).filter { it > 0 }.forEach { sum+=it }
println(sum)
}
- 柯里化、扩展函数
//sumFun01与sumFun02是等价的
fun sumFun01(x:Int) = { y:Int -> x + y}
//柯里化的方式实现
fun sumFun02(x:Int) :(Int) -> Int{
return {y:Int -> x + y }
}
fun sumFun03(x:Int,y:Int,z:Int) = x + y + z
fun sumFun04(x:Int) = {y:Int ->{z :Int -> x + y + z}}
fun funBlock(block:() -> Unit){
block()
}
fun funBlock(x:Int,block: (Int) -> Unit){
block(x)
}
fun main(){
println(sumFun01(1)(2))
println(sumFun02(1)(2))
println(sumFun03(1,2,3))
println(sumFun04(1)(2)(3))
funBlock(object : () -> Unit {
override fun invoke() {
println("block")
}
})
//与上面的方法调用相同,采用柯里化的方式
funBlock { println("block") }
funBlock(10,object :(Int) -> Unit{
override fun invoke(p1: Int) {
println(p1)
}
})
//与上面的方法调用相同,采用柯里化的方式
funBlock(10){
println(it)
}
val a = A()
a.a()
a.b()
}
//扩展函数
fun A.b(){
println("b")
}
class A{
fun a(){
println("A")
}
}
- 面向表达式编程
//Lambda表达式,类型为(Int) -> Int
{x:Int -> x + 1}
//函数体表达式,类型为(Int) -> Unit
fun (x : Int){println(x)}
//if-else表达式,类型为Int
if (x > 1) x else 1
//复合表达式,try表达式和if表达式结合使用
val res:Int? = try{
if (result.success){
jsonDecode(result.response)
}else{
null
}
} catch (e:JsonDecodeException){
null
}
fun main(){
//?: Elvis运算符或null合并运算符
val maybeInt:Int? = null
maybeInt ?:1 //maybeInt值为1
}
- 枚举类
//枚举类
enum class Day1{
MON,
TUE,
WEN,
THU,
FRI,
SAT,
SUN
}
enum class Day2(val day:Int){
MON(1),
TUE(2),
WEN(3),
THU(4),
FRI(5),
SAT(6),
SUN(7);
fun getDayNumber():Int{
return day
}
}
fun main(){
val day = Day2.FRI
println(day.getDayNumber())
}
- when表达式
//when表达式
fun main(){
val a = 10
when (a){
1 -> 1
2 -> 2
else -> 3
}
when{
a == 1 -> 5
a > 1 -> 6
else -> 7
}
}
fun whenMethod(fail:Boolean,score:Int) = when{
score == 60 -> 60
score in 61..79 -> 80
fail -> 50
else -> 100
}
- for循环和范围表达式
//for循环和范围表达式
fun main(){
//其中1..10就是范围表达式,"abc" .. "xyz"
for (i in 1 .. 10) println(i)
for (j : Int in 1..10){
println(j)
}
//步长为2
for (i in 1 ..10 step 2) println(i)
//倒序
for (i in 10 downTo 1 step 2) println(i)
//1至9,不包含10
for (i in 1 until 10) println(i)
"a" in listOf("a","b","c") //是否在其中,true
"a" !in listOf("b","c") //是否不在其中,true
"kot" in "abc" .."xyz"
val array = arrayOf(10,20,30)
for (c in array) println(c) //遍历数组
//遍历数组,同时获取索引与值
for ((index,value) in array.withIndex()){
println("index = $index,value = $value")
}
}
- 中缀表达式
//中缀表达式,标准库里的to
//infix fun<A,B> A.to(that:B):Pair<A,B>
//A 中缀方法 B
//中缀函数必须是某个类的扩展函数或成员方法,且只能有一个参数,参数不能有默认值
class Person{
infix fun called(name: String){
println("name = $name")
}
}
//vararg代表可变参数
fun printLetters(vararg letters:String,count:Int):Unit{
print("$count letters are ")
for (letter in letters) print(letter)
}
fun main(){
mapOf(
1 to "one",
2 to "two"
)
val p = Person()
p.called("Jane")
p called "Angel"
val letters = arrayOf("A","B","C")
//*g来传入可变参数
printLetters(*letters, count = 3)
}