1.只读变量和可修改变量
val:只读变量
var:可修改变量
编译时常量,必须在编译时赋值,在函数之外声明(const val MAX = 200) (函数都是在运行时调用,所以函数内的变量是在运行时赋值的)
编译时常量只能是常见的基本数据类型:String Int Double Float Long Short Byte Char Boolean
查看Kotlin编译之后的字节码:
1.shift*2
2.Tools->Kotlin->Show Kotlin Bytecode
2.表达式
if-else:
val a = if(boolean类型) “true” else “false”
when:
val school = "小学"
val level: Any = when (school) {
"学前班" -> "幼儿"
"小学" -> "少儿"
"中学" -> "青少年"
else -> {
println("未知")
}
}
range:
1..24:1<=x<=24
3. 具名函数
//使用:fix(age=10,name="Rose"),不用管参数顺序
//参数可以给默认值
//具名函数要写return语句
fun fix(name: String, age: Int = 2) {
println(name + age)
}
4.Unit类型和Nothing类型
Unit:无返回值 Nothing:如TODO函数的任务就是抛出异常,永远不能运行成功,返回Nothing类型
5.匿名函数(lambda表达式)
val total = "Mississippi".count()
//如果一个函数的lambda参数排在最后,或者是唯一的参数,
//那么括住lambda值参的一对圆括号就可以省略
val total1 = "Mississippi".count { letter ->
letter == 's'
}
/*val total1 = "Mississippi".count ({ letter ->
letter == 's'
})*/
val total2 = "Mississippi".count {
it == 's'
}
//method变量的类型是(String) -> String
//匿名函数不需要return,自动返回函数体最后一行结果
//无参匿名函数(: () -> String可省略,自动推断类型)
var method: () -> String = {
val holiday = "Vlentine's Day."
"Happy $holiday !"
}
//有参匿名函数(参数是name,String类型,返回值String类型 )
//调用method1("Jack")
var method1: (String) -> String = { name ->
val holiday = "Valentine's Day."
"$name , Happy $holiday !"
}
//有参匿名函数(匿名函数只有一个参数时,可以用it关键字代替参数 )
var method2: (String) -> String = {
val holiday = "Valentine's Day."
"$it , Happy $holiday !"
}
//不使用类型推断
var method3: (String, Int) -> String = { name, year ->
val holiday = "Valentine's Day."
"$name , Happy $holiday $year!"
}
//使用类型推断
var method4 = { name: String, year: Int ->
val holiday = "Valentine's Day."
"$name , Happy $holiday $year!"
}
6.一个函数作为另外一个函数的参数
fun main(){
//获取促销文案
/*val getDiscountWords = {goodsName:String,hour:Int ->
val currentYear = 2027
//$变量名后要加空格,或者用大括号括起来
"$currentYear 年,双11$goodsName 促销倒计时: ${hour}小时"
}
//展现,传入goodsName和getDiscountWords变量,执行showOnBoard,此处只是将变量传入
showOnBoard("卫生纸",getDiscountWords)*/
//以上调用showOnBoard函数的省略写法
showOnBoard("卫生纸"){goodsName:String,hour:Int ->
val currentYear = 2027
//$变量名后要加空格,或者用大括号括起来
"${currentYear}年,双11$goodsName 促销倒计时:${hour}小时"
}
}
//使用内联函数,提高使用lambda表达式后程序的性能,但使用lambda的递归函数无法内联,会导致无限循环
inline fun showOnBoard(goodsName:String,getDiscountWords:(String,Int) -> String){
//shuffled打乱顺序取last最后一个值
val hour = (1..24).shuffled().last()
//在这里相当于真正调用getDiscountWords函数
println(getDiscountWords(goodsName,hour))
}
函数的参数列表中除了可以传lambda,还可以传具名函数
fun main(){
//要获得函数引用,使用::操作符,后面跟要引用的函数名
showOnBoard("卫生纸",::getDiscountWords)
}
fun showOnBoard(goodsName:String,getDiscountWords:(String,Int) -> String){
//shuffled打乱顺序取last最后一个值
val hour = (1..24).shuffled().last()
//在这里相当于真正调用getDiscountWords函数
println(getDiscountWords(goodsName,hour))
}
fun getDiscountWords(goodsName:String,hour:Int): String {
val currentYear = 2027
//$变量名后要加空格,或者用大括号括起来
return "${currentYear}年,双11$goodsName 促销倒计时:${hour}小时"
}
7.返回类型是函数类型
fun main(){
val getDiscountWords = configDiscountWords()
println(getDiscountWords("syf"))
}
//返回类型是函数类型,configDiscountWords不需要传参,返回函数需要传String类型的参数
fun configDiscountWords(): (String) -> String {
return { it ->
"$it"
}
}
8.闭包
return后的lambda表达式可以引用它作用域外的变量age和sex
fun main(){
val getDiscountWords = configDiscountWords()
println(getDiscountWords("syf"))
}
fun configDiscountWords(): (String) -> String {
val age = 22
val sex = "女"
return { it ->
"姓名:$it,性别:$sex,年龄:$age........."
}
}
作用域呈现出以下状态:
java实现:
public static void main(String[] args){
showOnBoard("牙膏", new DiscountWords() {
@Override
public String getDiscountWords(String goodsName, int hour) {
return "2027年,双11" + goodsName + "促销倒计时:" + hour + "小时";
}
});
}
public interface DiscountWords {
String getDiscountWords(String goodsName, int hour);
}
public static void showOnBoard(String goodsName, DiscountWords discountWords) {
int hour = new Random().nextInt(24);
System.out.println(discountWords.getDiscountWords(goodsName, hour));
}
9.可空性(变量默认为非空)
?:代表可空
?.:安全调用操作符,可空时使用
!!.:非空断言操作符,当变量值为null时,会抛出KotlinNullPointerException
var str:String? = "butterfly"
str = null
println(str?.capitalize())//会输出null
var str:String? = "butterfly"
str = ""
str = str?.let{
if(it.isNotBlank()){
it.capitalize()//输出Butterfly
}else{
"butterfly"
}
}
println(str)
let标准函数返回的是匿名函数(lambda表达式)最后一行执行的结果
var str: String? = "butterfly"
str = null
println(str!!.capitalize())//str为空会报KotlinNullPointException
//如果str为空,则输出jack,否则输出str
println(str ?: "jack")
//如果str为空,则为jack,否则为str并首字母大写
str = str?.let { it.capitalize() } ?: "jack"
10. 自定义异常
onCreate:
var number:Int? = 0
try {
checkOperation(number)
number = number!!.plus(3)
println(number)
}catch (e:Exception){
println(e)
}
fun checkOperation(number: Int?){
number ?: throw UnskilledException()
}
class UnskilledException:IllegalArgumentException("操作不当")
以上代码输出3,如果number为空,输出:com.example.kotlintest.MainActivity$UnskilledException: 操作不当
11.字符串操作
//substring
val name = "Jimmy's friend"
val index = name.indexOf('\'')
// val str = name.substring(0,index)
val str = name.substring(0 until index)
println(str)
//split
val names = "Jack,Sunny,Jimmy,xiexie"
val (a,b,c,d) = names.split(',')//split返回值是list,给多个变量赋值
println("$a $b $c $d")
//replace
val strings = "I am so poor that i can not afford a cake!"
val str2 = strings.replace(Regex("[aeiou]")){//正则表达式Regex
when(it.value){
"a" -> "8"
"e" -> "6"
"i" -> "4"
"o" -> "2"
"u" -> "0"
else -> it.value
}
}
println("strings:$strings,str2:$str2")
12.字符串比较:(==:字符是否匹配,===:检查两个变量是否只想内存堆上同一对象)
val str3 = "Jason"
val str4 = "Jason"
println(str3 == str4)//true
println(str3 === str4)//true
val str3 = "Jason"
val str4 = "jason".capitalize()
println(str3 == str4)//true
println(str3 === str4)//false
13.字符串遍历
"I am so poor that i can not afford a cake!".forEach {
print("$it *")//打印不出来,只能通过logcat显示:This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
Log.d("syf","$it *")
}
14.数字类型的安全转换函数
//抛出异常,转换失败
//val num: Int = "8.98".toInt()
val num:Int? = "8.98".toIntOrNull()
println(num)
15.Double转Int和类型格式化
println(8.956756.toInt())
println(8.956756.roundToInt())
val s = "%.2f".format(8.956756)
println(s)
16.标准库函数
apply: 可以看做一个配置函数,可以传入一个接受者,然后调用一系列函数来配置它以便使用,他会返回配置好的接受者
val file1 = File("E://i have a dream_copy.txt")
file1.setReadable(true)
file1.setWritable(true)
file1.setExecutable(false)
val file2: File = File("E://i have s dream_copy.txt").apply {
setReadable(true)
setWritable(true)
setExecutable(false)
}
let:会把接受者穿给lambda,而apply什么都不传,匿名函数执行完,let会返回lambda的最后一行
val result = listOf(3, 2, 1).first().let {
it * it
}
println(result)
//调用
println(formatGreeting("Jack"))
println(formatGreeting(null))
fun formatGreeting(guestName: String?): String {
return guestName?.let {
"Welcome,$it."
} ?: "What's your name?"
}
run:光看作用域行为,run和apply差不多,但与apply不同,run函数不返回接受者,run返回的是lambda结果。
读取文件:
val file = File("E://i have a dream_copy.txt")
val result = file.run {
readText().contains("great")//读取文件
}
println(result)
判断是否过长:
//::调用函数
val result = "The people's Republic of China.".run(::isLong)
println(result)
}
fun isLong(name: String) = name.length >= 10
体现优势:
//::调用函数
"The people's Republic of China."
.run(::isLong)
.run(::showMessage)
.run(::println)
}
fun isLong(name: String) = name.length >= 10
fun showMessage(isLong:Boolean):String{
return if(isLong){
"Name is too long."
}else{
"Please rename."
}
}
with:run的变体,但with的调用方式不同,调用with时需要值参作为其第一个参数传入
with和run的区别:
val result1 = "The people's Republic of China.".run {
length >= 10
}
val result2 = with("The people's Republic of China.") {
length >= 10
}
also:和let一样,also也是把接受者作为值参传给lambda,但是also返回接受者对象,而let返回lambda结果,所以also尤其适合针对同一原始对象
var fileContents:List<String>
File("E://i have a dream_copy.txt")
.also {
println(it.name)
}.also {
fileContents = it.readLines()
}
println(fileContents)
takeIf:
val result = File("C://i have a dream_copy.txt")
.takeIf { it.exists() && it.canRead() }
?.readText()
println(result)
takeUnless:
val result = File("C://i have a dream_copy.txt")
.takeUnless { it.isHidden }
?.readText()
filter: 筛选满足lambda最后一行的元素并返回
17.集合
val list = listOf("Jason","Jack","Jacky")
println(list.getOrElse(4){"Unknown"})
println(list.getOrNull(4))
println(list.getOrNull(4) ?: "Unknown")
可变集合:
val mutableListOf = mutableListOf("Jason", "Jack", "Jacky")
mutableListOf.add("Jimmy")
mutableListOf.remove("Jack")
println(mutableListOf)
//可变与不可变list互转
listOf("Jason","Jack","Jacky").toMutableList()
mutableListOf("Jason", "Jack", "Jacky").toList()
可变集合的遍历:
val list = mutableListOf("Jason", "Jack", "Jacky")
list.add("Jimmy")
list.remove("Jack")
for(s in list){
println(s)
}
list.forEach{
println(it)
}
list.forEachIndexed { index, item ->
println("$index,$item")
}
mutator函数的使用:
val mutableListOf = mutableListOf("Jacky", "Jack", "Jimmy")
// mutableListOf.add("Jerry")
// mutableListOf.remove("Jack")
//新增函数
mutableListOf += "Rose"
//删除函数
mutableListOf -= "Jacky"
//使用lambda表达式删除元素
//先在lambda判断元素是否存在,当元素存在返回true,则删除元素
mutableListOf.removeIf {
it.contains("Jack")
}
for (s in mutableListOf) {
println(s)
}
解构语法过滤元素:
//不想给变量赋值,过滤元素,用_代替
val (origin,_,proxy) = mutableListOf
Set创建与元素获取:
val setList = setOf("Kotlin", "Java", "Scale","Java")
println(setList.elementAt(2))
val mutableSetOf = mutableSetOf("Kotlin", "Java", "Scale", "Java")
mutableSetOf += "C++"
集合转换和快捷函数:
val list = listOf("Kotlin", "Java", "Scale", "Java")
.toSet()
.toList()
println(list)
println(listOf("Kotlin", "Java", "Scale", "Java")
.distinct())
数组集合:
val intArray = intArrayOf(10,30,40)
listOf(10,30,40).toIntArray()
//file数组
val arrayOf = arrayOf(File("xxx"), File("yyyy"))
Map集合:
//创建map的两种方式
val mapOf1 = mapOf("Jack" to 20, "Jason" to 18, "Jack" to 30)
val mapOf2 = mapOf(Pair("Jimmy", 20), Pair("Jacky", 20))
//读取map的值
println(mapOf1["Jack"])
println(mapOf1.getValue("Jack"))
println(mapOf1.getOrElse("Rose") { "Unknown" })
println(mapOf1.getOrDefault("Rose", 0))
//遍历map
mapOf1.forEach {
println("${it.key},${it.value}")
}
mapOf2.forEach { (key: String, value: Int) ->
println("$key,$value")
}
//可变Map集合
val mutableMapOf = mutableMapOf("Jack" to 20, "Jason" to 18, "Jack" to 30)
mutableMapOf += "Jimmy" to 30
mutableMapOf.put("Jimmy",31)
mutableMapOf.getOrPut("Rose"){18}
println(mutableMapOf)
18.定义类
field关键字:
class Player {
var name: String = "jack"
get() = field.capitalize()
set(value) {
field = value.trim()
}
}
fun main() {
var p = Player()
println(p.name)
p.name = " rose "
println(p.name)
}
当get、set方法与属性(此处是name)无关时,不需要用到field。如下图,get方法的结果是1-6随机排序的第一个数。
19.对象初始化
主构造函数:
class PlayerSecond(
//_开头表示临时变量
_name: String,
_age: Int,
_isNormal: Boolean
) {
var name = _name
get() = field.capitalize()
set(value) {
field = value.trim()
}
var age = _age
get() = age.absoluteValue
set(value) {
field = age.absoluteValue
}
var isNormal = _isNormal
}
fun main(){
val p = PlayerSecond("Jack", 20, true)
p.name = "rose"
}
在主构造函数中定义属性:
class PlayerSecond(
//_开头表示临时变量
_name: String,
var age: Int,
var isNormal: Boolean
) {
var name = _name
get() = field.capitalize()
set(value) {
field = value.trim()
}
}
次构造函数:
class PlayerSecond(
//_开头表示临时变量
_name: String,
var age: Int,
var isNormal: Boolean
) {
var name = _name
get() = field.capitalize()
set(value) {
field = value.trim()
}
//次构造函数
constructor(name:String):this(name,age = 10,isNormal = false)
constructor(name:String,age:Int):this(name,age = 10,isNormal = false){
this.name = name.toUpperCase()
}
}
fun main(){
val p = PlayerSecond("Jack", 20, true)
// p.name = "rose"
//调用次构造函数
val p2 = PlayerSecond("Rose")
val p3 = PlayerSecond("Jacky",20)
println(p3.name)
}