Kotlin学习笔记(三)--kotlin更方便的写法

kotlin笔记第三篇

一.构造器

1.主构造器

之前的构造器写法:

class User {

    var name: String = "jack"
    var age = 10

	//使用constructor关键字
    constructor(name: String, age: Int) {
        this.name = name
        this.age = age
    }

}

可以简化为主构造器(1或者0个)的形式(类中的构造器是次构造器(不限个数))

//之前的形式编辑器会有提示,alt+enter就可以转化为主构造器的形式
class User constructor(name: String, age: Int) {
    var myName = name // name就是构造器传递的参数
}

主构造器的参数还可以在init代码块中使用,init代码块在主构造器后执行

class User constructor(name: String, age: Int) {
    var myName = name // name就是构造器传递的参数

    //init代码块在主构造器之后就执行
    init {
        var mySlogan = "我叫$name"
    }
}

类中声明了主构造器,则

必须性:创建类的对象时,不管使用哪个构造器,都需要主构造器的参与
第一性:在类的初始化过程中,首先执行的就是主构造器

如果有主构造器,次构造器必须关联主构造器用this()调用

class User(name: String) {
    var myName = name // name就是构造器传递的参数

    //init代码块在主构造器之后就执行,优先于次构造器
    init {
        var mySlogan = "我叫$name"
    }

    //如果有主构造器,次构造器必须关联主构造器用this()调用 
    //次构造器
    constructor(name: String, age: Int) : this(name) {

    }

    //次构造器
    constructor(name: String, age: Int, address: String) : this(name, age) {

    }
}

主构造器的constructor可以省略,但主构造器有可见性修饰符或注解,则不能省略

例如

class User private constructor(name: String) {
    //主构造器使用private修饰,constructor不能省略
    //外部无法调用主构造器
}

2.主构造器声明属性

在主构造函数的参数里使用var或者val,等价于该类声明了该属性,且初始值默认是主构造函数传递的参数值

class User constructor(var name: String) {
	//使用var 修饰参数
}

二.函数简化

1.使用=连接返回值

有返回值的

class User {
    //有返回值
    fun getSolgan(name: String): String = "我叫$name"

    //没有返回值,即返回值类型是Unit
    fun saySolgan(name: String) = L.d("我叫$name")

    //测试
    fun test() {
        val slogan = getSolgan("Jack")
        L.d(slogan)
    }
}

2.方法重载

kotlin中方法重载可以通过使用参数默认值来简化,比如,

java

public void eat(String food) {
    L.d("吃了" + food);
}
public void eat(String food, int count) {
    L.d("吃了" + count + "个" + food);
}

kotlin中,只需要一个函数即可完成方法重载

//count参数的默认值是2
fun eat(food: String, count: Int = 2) {
    L.d("吃了" + count + "个" + food)
}

调用

val user: User = User()
user.eat("雪糕")
user.eat("雪糕", 4)

3.命名参数

如果默认参数在前

//count参数的默认值是2,在无默认food前
    fun eat(count: Int = 2, food: String) {
        L.d("吃了" + count + "个" + food)
    }

再想调用默认参数的方法,即不传递count

val user: User = User()
user.eat("雪糕")//报错

可以显示的指出传递的参数值,如下

val user: User = User()
user.eat(food = "雪糕")//显示指出food的值,则默认的count即可生效

Kotlin 中的每一个函数参数都可以作为命名参数

命名参数对应的是位置参数,按照顺序传入参数

当一个函数被调用时,如果混用位置参数与命名参数,那么所有的位置参数都应该放在第一个命名参数之前:
val user: User = User()
user.eat(food = "雪糕", count = 3)//都用命名参数调用
user.eat(food = "雪糕", 3)//报错,混用的时候,位置参数要放在前边
user.eat(3, food = "雪糕")//混用的时候,位置参数要放在前边,正常

4.本地函数 (嵌套函数)
即函数内部声明函数,用于不需要再另写暴露在外的函数,仅自己处理,java无法内部再创建函数

普通的登录函数

//登录
fun login(userName: String, passWord: String, errorMessage: String) {
    //验证用户名不为空
    if (userName.isEmpty())
        throw IllegalArgumentException(errorMessage)
    //验证密码不为空
    if (passWord.isEmpty())
        throw IllegalArgumentException(errorMessage)
}

修改为嵌套函数

//登录
fun login(userName: String, passWord: String, errorMessage: String) {
	//内嵌的函数
    fun validate(argument: String) {
        if (argument.isEmpty()) {
       		//参数errorMessage是外部的变量,可以由内部函数访问
            throw java.lang.IllegalArgumentException(errorMessage)
           }
    }
    //验证用户名不为空
    validate(userName)
    //验证密码不为空
    validate(passWord)
}

其中的validate函数也可以替换为,用到了lambda表达式和require函数

fun validate(argument: String) {
    require(argument.isNotEmpty()) { errorMessage }
}

三.字符串

1.字符串拼接
字符串拼接,java中用+号或者String.format()函数、StringBuilderStringBuffer等处理

kotlin中使用$来处理,之前的例子中也有

val name = "Jack"
L.d("我叫$name,帅气的男人$name")

$还可以跟表达式用{}包括起来

val name = "Jack"
L.d("我叫$name,帅气的男人$name")
L.d("名字长度是: ${name.length}")

2.原生字符串(raw string)

使用""" """包括,转义字符无效,但是可以添加变量

val text = """
      Hi $name!
    My name is $myName.\n
"""

可以使用trimMargin对齐文本

val text = """
      |Hi world!
    |My name is kotlin.
""".trimMargin()

四.数组和集合

forEach遍历每一个元素

class ArrayTest {

    val intArray: IntArray = intArrayOf(4, 5, 6)
    val strList: List<String> = listOf("a", "b", "c")

	//用到了lambda 和 闭包
    fun test() {
        intArray.forEach { i -> L.d("值是$i") }
        strList.forEach { i -> L.d("值是$i") }
    }
}

filter对每个元素进行过滤操作,不符合就剔除,生成新的集合

//保留小于5的数,注意最后返回的是list
val convertList: List<Int> = intArray.filter { i -> i < 5 }

map遍历每个元素并执行给定表达式,最终形成新的集合

//保留小于5的数,注意最后返回的是list
val convertList: List<Int> = intArray.filter { i -> i < 5 }
//每个元素+3后 生成新的list
val convertList2: List<Int> = intArray.map { i -> i + 3 }

flatMap遍历每个元素,并为每个元素创建新的集合,最后合并到一个集合中

//保留小于5的数,注意最后返回的是list
val convertList: List<Int> = intArray.filter { i -> i < 5 }
//每个元素+3后 生成新的list
val convertList2: List<Int> = intArray.map { i -> i + 3 }
//每个元素都拼成一个列表,最后合并成一个总的列表
val convertList3: List<String> = strList.flatMap { listOf("改变 $it", "a", "b") }

range区间的意思,也就是范围,是kotlin里的数据类型

val range: IntRange = 0..1000 //闭区间 [0, 1000] 还有CharRange 、LongRange
val range2: IntRange = 0 until 1000 //半开区间 [0, 1000)

经常用作遍历

for (i in range) {
}
//每次间隔2个 输出:0, 2, 4, 6, 8, 10,....1000,
for (i in range2 step 2) {
    
}
//递减 downto 输出:100, 99, 98, ...51, 50
for (i in 100 downTo 50) {
    
}

Sequence又被称为「惰性集合操作」 用于数据量比较大或数据量未知的时候

//sequence,用到返回值的时候才执行流程,按顺序每个元素执行map再过滤,符合就退出,不符合就继续下一个元素
val sequence: Sequence<Int> = sequenceOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
val result: List<Int> = sequence.map { i -> i + 5 }
    .filter { i -> i % 5 == 0 }.toList()
print(result)
//普通的list,按顺序执行,流程是先生成每个元素加5的list,再过滤
val sequence2: List<Int> = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
val result2: List<Int> = sequence2.map { i -> i + 5 }
    .filter { i -> i % 5 == 0 }
print(result2)

Sequence优点:
1.一旦满足遍历退出的条件,就可以省略后续不必要的遍历过程
2.List 每次调用都会生成新的Iterable,会导致额外的内存消耗。Sequence 在整个流中只会有一个。

五.条件控制

if/else等价java的三元表达式

val max = if (a > b) {
    println("max:a")
    a // 返回 a
} else {
    println("max:b")
    b // 返回 b
}

when,类似java swtich,分支的最后一行结果可以当做返回值

val value: Int = when (x) {
    1 -> { println("1") }
    2 -> { println("2") }
    else -> { println("else") } // 默认分支,同java的default
}

如果多个分支同样的代码,

when (a) {
    1 -> {
        println("1")
    }
    2, 3 -> {  //用逗号隔开
        println("2")
    }
    else -> {
        println("else")
    }
}

when的分支判断可以用isin,和布尔表达式

when (a) {
    in 1..10 -> println("在1-10中间")
    in listOf(1, 2) -> println("在list中")
    !in 10..100 -> println("不在10-100中间")
}

when (a) {
    is Int -> println("是int类型")
    is String -> println("是字符串类型")
}

when {  //分支为true则执行该分支代码
    b.contains("a") -> println("b中包含a")
    b.contains("b") -> println("b中包含b")
}

for循环,遍历实现Iterable接口的数据

val array = intArrayOf(1, 2, 3, 4)
for (item in array) { //不用像java一样显示声明遍历的类型
    // 逻辑代码
}

//也可遍历区间
for (i in 0..10) { 
    println(i)
}

try-catch,kotlin中的try-catch和java写法没有区别,但是java的异常会检查,kotlin只会在运行时才会检查。
·?.?:

val str: String? = "NiHao"
val size: Int = str?.length //报错,如果str是null,则类型返回错误

修改为

val str: String? = "NiHao"
val size: Int = str?.length ?: -1 // 如果不为null,则返回他的长度,如果为null,则返回-1

=====
==java中,如果是基本数据类型,则判断值是否相等,如果是String类型,则判断表示引用地址是否相等String内容是否相等使用equals()

kotlin
==可以对基本数据类型以及String进行内容比较,相当于 Java 中的 equals()
===对引用的内存地址进行比较,相当于 Java 中的==

val str1 = "123"
val str2 = "123"
println(str1 == str2)  //打印true
val str1= "字符串"
val str2 = str1
val str3 = str1
print(str2 === str3)  // 内存地址相等,打印true
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值