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

这篇文章简单梳理下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
  • 内联只能访问内联
  • 参数不能被存
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容