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()
函数、StringBuilder
、StringBuffer
等处理
而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
的分支判断可以用is
,in
,和布尔表达式
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