美文网首页
Kotlin学习笔记(一)-语法糖

Kotlin学习笔记(一)-语法糖

作者: Stan_Z | 来源:发表于2020-12-13 21:28 被阅读0次

这篇文章简单梳理下Kotlin的语法糖。

一、内置类型

1.1 基本类型
  • 整数类型:Byte、Short、Int和Long,Int是默认类型
  • 浮点类型:Float和Double,Double是默认类型
  • 字符类型:Char
  • 布尔类型:Boolean
    增加无符号类型:UByte、UShort、Uint、ULong

Kotlin数据基本类型均为对象类型。

Unit 等同于void,Any等同于Object,这是kotlin与java区别的地方。

  • var 变量
  • val 只读变量 //作为局部变量等价于java final常量,而作为全局变量可以配置get方法,return值可以不同。
  • const val 全局静态常量
类型自动推导

var b:Int =2 推导为:var a = 2
注:不能直接声明var a,要么初始化var a = 2,要么声明好类型var a : Int

强制类型转换

var l = 1L
var d = l.toDouble() //这里不像java,类型转换必须主动调用toXXX()

字符串比较:

== 比较内容 equals
===比较地址 ==

字符串模版

val c = "world"
println("hello $c”)

Raw字符串
val n = """
           <!doctype html>
           <html>
           <head>
               <meta charset="UTF-8"/>
           </head>
           <body>
               <div id="container">
                   <H1>Hello World</H1>
               </div>
           </body>
           </html>
           """.trimIndent()//trim掉公共的空白
别名

typealias ArrayList<E> = java.util.ArrayList<E>

空类型安全
操作符 描述
? 可空操作符,声明可空类型。 var str:String? = "aaa"
?. 安全调用操作符,为空返回null。str?.length
?.let{} ?.与let一起使用,用于遍历集合时,则忽略null值,只对非空值执行操作。
for (item in listWithNulls) {
    item?.let { println(it) } // 输出 abc 并忽略 null
}
?: Elvis操作符,检查结果为空返回后面的值。val a = b?.length ?: 0
!! 非空断言运算符,将任何值转换为非空类型,若该值为空则抛出NPE。
as? 尝试转换成指定类型,如果尝试转换不成功则返回null。var b: Int ? = a as? Int
filterNotNull 过滤一个可空类型元素集合中的非空元素。val list: List<Int> = nullableList.filterNotNull()

另外普调类型与对应的空类型的继承关系:
String 是String?的子类

var x:String = “Hello”
var y:String? = “World”
x = y // 不行,编译器报type mismatch错误
y = x //可以

String! 为平台类型,无法判断是否为空,需要开发者自己去做安全访问。

附:看类型快捷键 shift+control+p

1.2 数组

IntArray //int[]
Array<Int> //Integer[] 对象类型 Array<Person>

数组的创建
val c0 = intArrayOf(1, 2, 3, 4, 5) //int[] arr = {1,2,3,4,5}
val c1 = IntArray(5) // int[] arr = new int[5]
val c2 = Array<Int>(5,{it})// 第二个参数是方法类型, init: (Int) -> T
数组的遍历

for each:

for (e in c0) {
   println(e)
}

c0.forEach {
   println(it)
}

for i:

for (i in c0.indices) {
   //i是对应的index
   println(c0[i])
  if(1 in e){// 对应元素是否在数组中,!in 对应元素不在数组中
     println(“1 exists in variable e"])
    }
}
1.3 区间

区间

val intRange = 1..10 // [1, 10]
val charRange = 'a'..'z'

开区间

val intRangeExclusive = 1 until 10 // [1, 10)
val charRangeExclusive = 'a' until 'z'

倒序区间

val intRangeReverse = 10 downTo 1 // [10, 9, ... , 1]
val charRangeReverse = 'z' downTo 'a'

步长

val intRangeWithStep = 1..10 step 2
val charRangeWithStep = 'a'..'z' step 2
1.4 运算符

直接查看官方文档
https://kotlinlang.org/docs/reference/operator-overloading.html

二、 集合

2.1 集合框架

这里一种写法就用java写法就行,区别就是不用new

var list = ArrayList<String>()
list.add("1")
println(list.get(0))

var map = HashMap<String,String>()
map.put("key","value")
println(map.get("key”))

也可以按标准kotlin写法:

val list = listOf(1, 2, 3)//不可变list(不能添加和删除元素)
val mutableList = mutableListOf(1, 2, 3)//可变list
val arrays = mutableListOf<Int>()//仅仅初始化,没有元素,必须指定泛型类型

val map = mapOf( //不可变map
   "a" to 1,
   "b" to 2
)

val mutableMap = mutableMapOf( //可变map
   "a" to 1,
   "b" to 2
)

val maps = mutableMapOf<Int,String>()

list操作:

mutableList.add(4) //set

mutableList.forEach {
   mutableList[2] = 5 //get
   println(it)
}

map操作

mutableMap["c"] = 3//set
mutableMap["c"]//get
mutableMap.set("c", 3)//java式写法set
mutableMap.get("c")//get

同时注意:
add 操作可用 += 代替, 同理remove 为 -=
例如:mutableList += 4

这里单独介绍下循环

for循环表达式

for(item in arrays){//item是每个元素
   print(item)
}

for(i in arrays.indices){
   print(array[i])
}

while与do..while这部分与java没区别

2.2 集合变换与序列
2.2.1 集合的映射操作:filter、map、flatMap
  • filter:保留满足条件的元素
    list.filter{it %2 == 0}
    变换序列:list.asSequence().filter{it %2 == 0} //.asSequence()类似java的 .stream

  • map:集合中的所有元素意义映射新集合
    list.map{it2+1}
    变换序列:list.asSequence().map{it
    2+1}

  • flatMap:集合中的所有元素意义映射新集合,并合并这些集合得到新集合
    list.flatMap{0 until it}.joinToString().let(::println)

.asSequence懒汉式操作案例:

val list = listOf(1, 2, 3, 4)
list.asSequence().filter {
   println("filter:$it")
    it % 2 == 0
}.map {
   println("map:$it")
    it * 2 + 1
}.forEach {
   println("foreach:$it")
}

打印结果:
filter:1
filter:2
map:2
foreach:5
filter:3
filter:4
map:4
foreach:9

去掉.asSequence对比:

list.filter {
   println("filter:$it")
    it % 2 == 0
}.map {
   println("map:$it")
    it * 2 + 1
}.forEach {
   println("foreach:$it")
}

打印结果:
filter:1
filter:2
filter:3
filter:4
map:2
map:4
foreach:5
foreach:9

这部分体会是有点类似于rxjava

2.2.2 集合的聚合操作 sum、reduce、fold
  • sum 所有元素求和

  • reduce 将元素依次按规则聚合,结果与元素类型一致

  • fold 给定初始化值,将元素按规则聚合,结果与初始化值类型一致
    list.fold(StringBuilder()){
    acc,i->acc.append(i)
    }

三、表达式

3.1 if表达式

kotlin可以把if表达式的结果赋值给一个变量

val max = if (a > b) a else b
3.2 when表达式

when 将它的参数和所有的分支条件顺序比较,直到某个分支满足条件。

c = when (x) {
        1 -> print("x等于1")
        in 10..20 -> print(“x在区间10-20范围内")
        else -> { //default
        }
     }

将条件转移到分支

var x:Any = …
c = when{
        x is String -> c = x.length
        x == 1 -> c = 100
        else -> c = 20
    }

括号内条件还能做赋值

c = when(var input = readLine()){ //since kotlin 1.3
    null -> 0
    else -> input.length
}

循环中才使用的返回与跳转,高阶函数forEach不能使用:

  • return。默认从最直接包围它的函数或者匿名函数返回。
  • break。终止最直接包围它的循环。
  • continue。继续下一次最直接包围它的循环。
3.3 try…catch表达式
c = try{
  a/b
}catch(e:Exception){
   e.printStackTrace()
   0
}
3.4 Lambda表达式

使用:
func()

Lambda表达式定义:


Kotlin

Lambda表达式参数省略

val f1:Function1<Int,Unit> = {p ->     
    println(p)
}

转为:

val f1:Function1<Int,Unit> = {   
    println(it)
}
3.5 SAM转换

一个参数类型问只有一个方法的Java接口的Java方法调用时可用lambda表达式做转换作为参数。

val eventManager = EventManager()

//匿名内部类:object:类型
val onEvent = object:EventManager.OnEventListener{
   override fun onEvent(event:Int){
     println(“onEvent $event") 
   }
}

eventManager.addOnEventListener(onEvent)
eventManager.removeEventListener(onEvent)

四、函数

kotlin函数有自己的类型,可以赋值、传递、并在合适的条件下调用

函数返回值支持类型推导。

4.1 函数类型:
4.2 函数的引用
变长参数:vararg

fun main(vararg args: String) {…}

4.3 多返回值

可以用Pair和Triple进行包装

Pair
val pair = "Hello" to "World"
val pair1 = Pair("Hello", "Kotlin")
val first = pair.first
val second = pair.second
val (x, y) = pair

Triple

val triple = Triple("a", 1, 1.0)
val first = triple.first
val second = triple.second
val third = triple.third
val (x, y, z) = triple

比如:

fun multiReturn():Triple<Int,Long,String>{
   return Triple(1,3L,"aaa")
}

fun main() {
    val (i, l, s) = multiReturn()
    println(i+l)
}

默认参数和具名参数

fun defaultParameter(x: Int = 5, y: String, z: Long = 0L){...}
fun main() {
   defaultParameter(y = "aaa")
}
4.4 高阶函数

参数类型包含函数类型或返回值类型为函数类型的函数为高阶函数

public inline fun <R> IntArray.map(transform: (Int) -> R): List<R> {//参数类型包含函数类型(Int) -> R,返回值类型包含函数类型List<R>
    return mapTo(ArrayList<R>(size), transform)
}

函数类型为最后一个参数可以移到括号外面,且省略小括号:

intArray.forEach{ it -> Unit
    println(it)
}

省略为:

intArray.forEach { print(it) }

intArray.forEach { print(it) } 又等价于  intArray.forEach(::print)   //::print 匹配类型为(Int) -> Unit的函数引用,可直接传入

完整案例:

fun cost(block: () -> Unit) {
    val start = System.currentTimeMillis()
    block()
    print("cost:${System.currentTimeMillis() - start}")
}

fun fibonacci(): () -> Long {
    var first = 0L
   var second = 1L
   return {
       val next = first + second
        val current = first
        first = second
        second = next
        current //return current
   }
}

fun main(args: Array<String>) {
    cost {
       val fib = fibonacci()
        for (i in 0..10) {
            print(fib())
        }
    }
}
4.5 内联函数 inline

函数体内的多个函数执行优化为一个函数体来执行,提升代码执行性能。常用于高阶函数,将参数函数和自身方法体合和一个函数体来执行。

inline fun cost(block: () -> Unit) {
    val start = System.currentTimeMillis()
    block()
    print("cost:${System.currentTimeMillis() - start}")
}
内联高阶函数的return
val ints = intArrayOf(1, 2, 3, 4)

ints.forEach {
   if (it == 3) return@forEach //仅仅跳出这一次内联函数的调用相当于continue,continue只能用在循环中
   print(it)
}
non-local return
ints.forEach {
   if (it == 3) return //直接退出
   print(it)
}

禁止non-local return :关键字 crossinline

inline fun Runnable(crossinline block:()->Unit):Runnable{ //也可以使用no inline block:()->Unit,禁止函数内联,这样前面的inline就没有意义了。
  return object : Runnable{
     override fun run(){
         block()
      }
   }
}

内联函数的限制

  • public/protected 的内联方法只能访问对应类的public成员
  • 内联函数的内联函数参数不能被存储(赋值给变量)
  • 内联函数的内联函数参数只能传递给其他内联函数参数

简而言之:

  • public 只能访问public
  • 内联只能访问内联
  • 参数不能被存

相关文章

网友评论

      本文标题:Kotlin学习笔记(一)-语法糖

      本文链接:https://www.haomeiwen.com/subject/benpgktx.html