Kotlin第二弹

1.变量与常量

val s1 : String = "Hello"
var s2 : String = "Kotlin"
var s3 = ""

在kotlin中,val用来修饰常量,初始化后就不能改变,var用来修饰变量。
例子中s1就是常量,s2就是变量。那么kotlin中的常量和java中的常量是不是一样的呢?答案是不全一样,java中的常量是用static final修饰,是我们常说的编译器常量,但是在kotlin中单单用val修饰并不是编译器常量,只有用const val修饰的常量才是编译器常量。
再讲一个概念,“类型推导”,s3变量声明的方式就是用到了类型推导,虽然没有指明类型,但是通过赋值可知s3就是String类型

2.函数

fun sum(arg1:Int,arg2:Int):Int{
    return arg1 +  arg2;
}

上面是一个最简单的求和函数,fun是声明函数的关键字,sum是函数名称,arg1和arg2是函数的Int类型的入参,返回值的类型是Int。

fun main(args: Array<String>) {

}

这是我们的main入口函数,发现少了什么?没有返回值?其实是kotlin的Unit类型,相当于java中的void类型,当返回值是Unit类型时可以省略,相当于下面的写法。

fun main(args: Array<String>):Unit{

}

除了这种简写方式,还可以用表达式作为返回值的简写方式。将例子进行改写

fun sum(arg1: Int,arg2: Int) = arg1 + arg2

是不是必须要有函数名呢?答案是no,因为有一种函数叫做匿名函数。

val sum = fun(arg1:Int,arg2:Int) = arg1 + arg2

上面就是一个求和的匿名函数,它被赋值给sum这个常量了,这个匿名函数的类型是(Int,Int)->Int,那他该怎么调用呢?

println(sum(1,2))
println(sum.invoke(1,2))

第一种方式很好理解,第二种方式是什么鬼?为什么我们随便定义的匿名函数会有一个invoke方法?我们可以打印下sum这个常量的类型

Function2<java.lang.Integer, java.lang.Integer, java.lang.Integer>

原来我们定义的匿名函数在kotlin中都能找到对应的类型,这个Function2表示有2个Int类型的入参和一个Int类型的出参,kotlin内置了从Function0到Function22这个多函数类型,每个类型都有一个invoke方法。

3.lambda表达式

lambda表达式其实就是匿名函数,只不过是进一步的简写。

    val stringArray : Array<String> = arrayOf("aa","abc","bbb","aaa","bc","ccc")
    //找出数组中带a的元素,并打印
    stringArray.filter { it.contains("a") }.forEach { println(it) }
    println("------")
    //找出数组中元素长度是3的元素,并打印
    stringArray.filter { it.length == 3 }.forEach { println(it) }
    println("------")
    //找出数组中元素中带小写c的,并把c装成大写,并打印
    stringArray.filter { it.contains("c") }.map { it.replace("c","C") }.forEach { println(it) }

上面这段代码就是使用了lambda表达式,原本要写循环表达式,条件表达式的代码一行代码就搞定了。filter用来过滤的,map用来批量处理的,forEach用来遍历的。
先看filter定义

public inline fun <T> Array<out T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}

这是一个Array类的扩展内联函数,它的入参接受一个T类型返回一个Boolean类型,函数返回一个List T类型

map定义

public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

这是Iterable类的扩展内联函数,它的入参接受一个T类型,返回一个R类型,函数返回一个List R类型

foreach定义

public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
    for (element in this) action(element)
}

这同样是一个Iterable类的扩展内联函数,它的入参接受一个T类型,返回一个Unit类型,函数返回一个Unit类型,所以foreach函数要放在最后面

我们尝试自己定义一些lambda表达式:

class Student(var name:String,var age:Int){

     fun filter(action:(Student)->Boolean): Student? {
        if (action.invoke(this))
            return this
        else
            return null
    }

    fun println(action:(Student)->Unit):Unit{
        action(this)
    }
}

val s : Student = Student("aaa",11)
s.filter { it.name.startsWith("a") }?.filter { it.age > 10 }?.println { println("${it.name}-${it.age}") }

我们自定义了Stdent类,并定义了filter和println两个函数,filter函数入参的lambda表达式传入一个Student,返回一个Boolean,函数返回Student?类型。println函数入参的lambda表达式传入一个Student,返回一个Boolean,函数返回Unit。这样我们也能用一行代码对student对象进行过滤打印,过滤规则和打印格式都通过lambda表达式传入。

关于lambda表达式后面会经常碰到,这里就先简单介绍下。

4.类的成员和方法

class ABC(var a:String,b:Int){
    var c : Int = 0
        get() {
            println("get c")
            return field
        }
        set(value) {
            println("set c")
            field = value
        }
}

上面这个ABC类,a和c是类的成员,b只是局部变量,只能在类内部使用.kotlin中类的成员变量会默认生成get/set方法,当然也可以重写,但是声明在构造器内部的成员变量只能使用默认的set/get方法。

关于类的成员变量初始化的一些问题。

class AAA(var a:String){
    var b : Int = 0
    var c : String? = null
    lateinit var d : String
    val e : IntArray by lazy { intArrayOf(1,2) }
}

上面这个AAA类中有5个成员变量,分别代表5种不同的初始化方式,a是在构造器中声明,要使用这个类必须要初始化a,b是Int类型,初始化赋值为了0,c被声明成了可空的String类型,并赋值为null,这种方式会为后面使用带来不变,d使用了lateinit关键字,作用是可以延迟初始化,但是使用前不初始化会崩溃,e使用了by lazy的懒加载方式

5.运算符重载

在java中并没有运算符重载的概念,kotlin中的运算符重载跟c++很相似,我们会自定义一个类,实现这个类的加减乘除的运算。

class BBB(var i :Int){
    operator fun plus(other:BBB):BBB{
        return BBB(this.i + other.i)
    }

    operator fun minus(other: BBB):BBB{
        return BBB(this.i-other.i)
    }

    operator fun times(other: BBB):BBB{
        return BBB(this.i*other.i)
    }

    operator fun div(other: BBB):BBB{
        return BBB(this.i/other.i)
    }

    override fun toString(): String {
        return "$i"
    }
}

自定义了BBB这个类,它有i这个Int类型的成员变量,BBB这个类定义了加减乘除四种运算符,实际上就是内部i这个成员变量进行运算。例子有点脱裤子放屁,但是基本能说明运算符重载的使用方式。

fun main(args: Array<String>) {
    val a = BBB(1)
    val b = BBB(2)
    val c = (a + b) * b / a
    println(c)
}

打印是6

6.条件表达式

条件语句和条件表达式的区别是条件语句是来控制流程的,而条件表达式可以被用来复制。本节主要讨论if和when的使用。
if作为条件语句的方式非常简单

var a : String?
    if (args[0].equals("-name")){
        a = args[1]
    }else{
        a = null
    }

这就是if条件语句。

var a : String? =
    if (args[0].equals("-name")){
        args[1]
    }else{
        null
    }

这就是if条件表达式.

kotlin中的when是java的switch的加强版,switch能实现的功能when都能实现,switch不能实现的when也能实现,好吊的!

when(args[0]){
        is String -> "String"
        "-name" -> args[1]
        in arrayOf("-java","-kotlin") -> args[2].toInt()
        else -> null
    }

不说了,自己体会吧。同样也可以作为表达式赋值给变量

var a : Any? =
    when(args[0]){
        is String -> "String"
        "-name" -> args[1]
        in arrayOf("-java","-kotlin") -> args[2].toInt()
        else -> null
    }

7.循环语句

var array = intArrayOf(1,2,3,4,5,6,7,8)
    for (i in array){
        println("$i")
    }

一般情况,我们都是用for...in语句来迭代对象,比如array,list等。但是有没有想过为什么这些对象可以使用for...语句呢?这是因为这些迭代对象都有iterator()方法,他会返回一个对应的迭代器对象,循环其实是在遍历这个迭代器?那么我们自己试试看,创建一个可以被迭代的对象。

class MyIntArray{
    private val list : MutableList<Int> = mutableListOf()

    fun add(i: Int){
        list.add(i)
    }

    fun remove(i: Int){
        list.remove(i)
    }

    operator fun iterator():MyIterator{
        return MyIterator(list.iterator())
    }
}

MyIntArray这个类内部有一个list对象来存储数据,同样有一个iterator方法返回一个MyIterator迭代器。

class MyIterator(var iterator: Iterator<Int>){

    operator fun next():Int{
        return iterator.next()
    }

    operator fun hasNext():Boolean{
        return iterator.hasNext()
    }

}

这就是MyIterator的实现,其实就是使用的是外部传入list的迭代器。

var array2 = MyIntArray()
    array2.add(10)
    array2.add(20)
    array2.add(30)
    array2.add(40)
    for (i in array2){
        println("$i")
    }

这是我们的测试代码,编译通过,输出正常,原来for...in遍历的就是迭代器,只要循环的对象有iterator方法,并返回一个正常的迭代器就能使用for...in循环。

除了for...in语句,还有while,do...while语句一样可以用于循环,对于array,list等对象,系统还定义了foreach这个函数用于lambda表达式去循环。

8.异常捕获

var s : String = ""
    try {
        s.toInt()
    }catch (e:Exception){
        e.printStackTrace()
    }finally {
        println("end")
    }

kotlin中的异常捕获跟java没什么区别,连关键字都一样。但是同样可以作为表达式为变量赋值。类似这样...

var s : String = ""
    var i = try {
        s.toInt()
    }catch (e:Exception){
        0
    }finally {
        println("end")
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容