Kotlin:变量和函数

518 阅读2分钟

前言

本专栏基于郭霖第一行代码第三版Kotlin知识编写,在此仰慕+感谢大佬,当初就是为了学习Kotlin买的这本书,果然大佬讲东西还是通俗易懂~彩虹屁安排一波🌈 至于为什么要输出这个专栏是因为为了将自己学习到的知识输出出来有所记录,毕竟输入不是学习,输出才是,这样也可以和大家一起交流学习。 这个专栏我会将本人学习到的关于Kotlin知识顺序渐进通俗的输出一遍,相信各位大佬看了之后一定会直呼牛批! 下面有请各位大佬观看通俗易懂Kotlin系列之第一篇文章——变量和函数 第一篇文章首先了解 变量、 函数、 逻辑控制语句、 面向对象 、lambda、 空指针处理 、内嵌表达式等知识

1:变量

##1.1:val和var val(value)用来声明一个不可变的变量,对应java中的final var(variable)用来声明一个可变的变量,对应java中的非final 在Java中一个良好的编程习惯是:除非一个变量被明确允许被修改否则他都应该被加上final变量 同样的在kotlin中为了保持代码的健壮性,我们都应该首先使用val来声明一个变量,在没有变法满足需求的时候再使用var

1.2:Kotlin中的类型推导机制

fun main() {
    val data = 10
    println("data的值是$data")
}

我们使用声明data赋值为10 kotlin会自动将data推导为整形变量 运行之后如我们所料

9395392-1f8fcef7b5d77cdf.webp 但是Koltin中的类型推导并不是总是正常工作,比如我们在对一个变量进行延时赋值的时候Kotlin就无法进行类型推导了 这时候就应该这样写:

    val data1: Int = 10
    println(data1)

1.3:Java和Kotlin数据类型对照表

9395392-2eba44d043d6f965.webp

2:函数

2.1:fun(function)是定义函数关键字,无论定义什么函数都需要使用fun来声明

我们只要掌握以下命名规范就可以掌握80%的编程场景

fun methodTest(num1: Int, num2: Int): Int {
    return max(num1, num2)
}

当函数中的代码只有一行代码的时候可以不用编写代码体,直接写在代码后边即可

fun methodTest(num1: Int, num2: Int): Int = max(num1, num2)

由于Kotlin有出色的类型推到机制 max函数返回必定是Int类型,因此我们可以继续简化代码

fun methodTest(num1: Int, num2: Int) = max(num1, num2)

3:逻辑控制语句

程序的执行语句主要分为三种:顺序语句、条件语句、循环语句

3.1:if条件语句

if语句kotlin和java没什么太大的区别,下面演示一段条件语句在Kotlin中如何使用和简化

fun getNum(num1: Int, num2: Int): Int {
    var result = 0
    if (num1 > num2) {
        result = num1
    } else {
        result = num2
    }
    return result
}

简化

fun getNum2(num1: Int, num2: Int): Int {
    var result = if (num1 > num2) {
        num1
    } else {
        num2
    }
    return result
}

再简化

fun getNum2(num1: Int, num2: Int): Int {
    return if (num1 > num2) {
        num1
    } else {
        num2
    }
}

我们上边说过代码体中只有一段代码的时候可以不写函数体 直接用=链接即可,另外kotlin有出色类型推导机制这里可以将Int直接省略 如下最终代码为:

fun getNum2(num1: Int, num2: Int) = if (num1 > num2) {
    num1
} else {
    num2
}

3.2:when条件语句

kotlin中的when语句跟java中的switch差不多,但是又比switch强大...

fun whenTest(name: String) = when (name) {
    "jingkai" -> 88
    "jingxiaokai" -> 100
    else -> 0
}

或者使用

fun whenTest2(name: String) = when {
    name == "Tom" -> 82
    name == "Jim" -> 11
    name == "Cha" -> 12
    else -> 0
}

另外也kotlin中的when也可以用来判断类型:

fun checkNum(num: Number) = when (num) {
    is Int -> println("是int")
    is Double -> println("是Double")
    else -> println("什么也不是")
}

is相当于java中的instanceof关键字

3.3:循环语句

for-in循环 区间: 0..10 代表0到10的闭区间 0 until 10 代表0到10 的左闭右开区间

fun forTest() {
    for (i in 0 until 10 step 2) {       
    }
}

如上代码代表在0到10的区间内每次都增加2,也就是使用step跳过复杂的逻辑 如果想要实现降序 可以使用 downto关键字

fun forTest() {
    for (i in 0 downTo 10 step 2) {
    }
}

4:面向对象编程

4.1:类与对象

在kotlin中创建对象

fun classTest() {
    val data = Data("jingkais", 1)
    data.height="178"
    data.weight="77"
}

4.2:继承与构造函数

Kotlin中的继承可以这样写 使用open声明一个类可以被继承 ,:表示 Student继承自Person

open class Person(val name: String,val age: Int) {
}
class Student( name: String,  age: Int) : Person(name, age) {
}

kotlin将构造函数分为了两种 主构造函数 和 次构造函数 主构造函数没有函数体直接写类名后边即可 声明和使用如下 因为在主构造函数中没有函数体 我们可以使用init函数来执行其它逻辑语句

class Student( name: String,  age: Int) : Person(name, age) {
    init {
        //书写逻辑
    }
}
val student = Student("jingkais", 18)

次构造函数: kotlin规定当一个类中机有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数 kotlin次构造函数用constructor关键字来定义的

class Student(name: String, age: Int) : Person(name, age) {
    init {
        //书写逻辑
    }
    constructor() : this("", 0)
    constructor(height: String, wight: String) : this("", 0)
}

另一种情况:只有次构造函数没有主构造函数

class Student : Person {
    constructor(name: String, age: Int) : super(name, age) {
    }
}

4.3:接口

kotlin中的接口跟java中的接口没有任何区别

interface StudyEnglish {
    fun doHomeWork()
    fun readBooks()
}
//调用
class Student : Person("", 1), StudyEnglish {
    override fun doHomeWork() {
        TODO("Not yet implemented")
    }
    override fun readBooks() {
        TODO("Not yet implemented")
    }
}

4.4:java和kotlin函数可见修饰符对照表

9395392-2e76affa5ba8ef36.webp

4.5:数据类与单列类

Kotlin中新建数据类 就是我们平常所说的的bean可以直接新建 包→New→Kotlin File/Class/Data class

data class Data(val name: String, val age: Int) {

}

并且kotlin会帮你将equals() hashCode() toString() 等固定且无实际意义的的方法自动生成

单列模式用于避免重复创建对象 减少资源的浪费 在kotlin中创建单列类十分简单 →New→Kotlin File/Object

object Singleton {
    fun singleTest() {
        println("单列类")
    }
}

4.6:Lambda编程

lambda分为基础知识、高阶函数、DSL等高级Lambda技巧

4.6.1:集合的创建与遍历

kotlin提供了内置listof(不可变)mutableListOf(可变)新建一个集合

 val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
 val list = mutableListOf("Apple", "Banana", "Orange", "Pear", "Grape")

set不可以存放重复的数据,同样set也存在 mutableSetOf(可变)

val set = setOf("Apple", "Banana", "Orange", "Pear", "Grape")

map集合,同样map也存在 mutableMapOf(可变)

val map = mapOf("Apple" to 1, "Banana" to 2, "Orange" to 3, "Pear" to 4, "Grape" to 5)

4.6.2:集合的函数式api

现在有一个需求:找到集合中单词最长的水果名 我们可以写出如下代码:

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
var maxLengthFruit = ""
for (fruit in list) {
 if (fruit.length > maxLengthFruit.length) {
 maxLengthFruit = fruit
 }
}
println("max length fruit is " + maxLengthFruit)

使用集合的函数式api可以简化成如下

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val maxLengthFruit = list.maxBy { it.length }
println("max length fruit is " + maxLengthFruit)

上边代码用到了Lambda表达式 ,我们来理解一下lanbda表达式的定义:一段可以作为参数传递的代码,语法结构如下: {参数名1: 参数类型, 参数名2: 参数类型 -> 函数体} 可以声明参数列表,参数列表结尾使用->符号表示参数列表的开始和函数体的开始,函数体重可以编写任意行代码(不建议写得太长),并且最后一行代码自动作为Lambda表达式的返回值
下边来解释一下上边的代码: maxBy函数是一个普通函数,他接受一个Lambda 只不过他在遍历集合的时候会将每次遍历的值传递到Lambda中, 他的工作原理就是根据我们传入的条件来遍历集合 所以我们代码可以写成如下:

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val lambda = { fruit: String -> fruit.length }
val maxLengthFruit = list.maxBy(lambda)

定义的lambda表达式如上所示,我们还可以继续简化代码 将Lambda直接放入到maxBy中:

val maxLengthFruit = list.maxBy({ fruit: String -> fruit.length })

kotlin规定当Lambda参数是函数的最后一个参数可以将Lambda移出到()外边

val maxLengthFruit = list.maxBy() { fruit: String -> fruit.length }

接下来如果lambda 参数是函数的唯一一个参数的话还可以省略括号

val maxLengthFruit = list.maxBy{ fruit: String -> fruit.length }

Lambda表达式中大多情况下不必进行参数类型声明:

val maxLengthFruit = list.maxBy{ fruit -> fruit.length }

另外如果代码中只有一个参数也可以不用声明参数名:

val maxLengthFruit = list.maxBy { it.length }

牛逼不牛逼吧 ,看管你湿了吗 另外集合中的map函数是最常用的一种函数式API,他用于将集合中的每个元素都映射成另一个值,映射规则根据Lambda来定 如果我们希望使集合中水果名都转化为大写:

fun main() {
 val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
 val newList = list.map { it.toUpperCase() }
 for (fruit in newList) {
 println(fruit)
 }
}

4.6.3:函数式api all和any

all判断集合中所有元素都满足指定条件 any判断集合中的元素至少有一个元素满足条件

fun main() {
 val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
 val anyResult = list.any { it.length <= 5 }
 val allResult = list.all { it.length <= 5 }
 println("anyResult is " + anyResult + ", allResult is " + allResult)
}

4.7:空指针检查

4.7.1:可空系统类型

在对象后添加?表示这个对象可能是空,使用对象的时候需要添加?.来进行判断 表示是空不执行,否则执行

fun doStudy(study: Study?) {
 study?.readBooks()
 study?.doHomework()
}

4.7.2: 判空辅助工具

编写函数来获取一段文本的长度使用传统的写法

fun getTextLength(text: String?): Int {
 if (text != null) {
 return text.length
 }
 return 0
}

借助操作符变得更简单 ?:操作符。这个操作符的左右两边都接收一个表达式, 如果左边表达式的结果不为空就返回左边表达式的结果,否则就返回右边表达式的结果。

fun getTextLength(text: String?) = text?.length ?: 0

!! 告诉Kotlin,我非常确信这里的对象不会为空,但是出现问题我会自己承担

fun printUpperCase() {
 val upperCase = content!!.toUpperCase()
 println(upperCase)
}

4.7.3: let标准函数

fun doStudy(study: Study?) {
 study?.readBooks()
 study?.doHomework()
}

上边的函数可以使用let函数进行优化 如下

fun doStudy(study: Study?) {
 study?.let { stu ->
 stu.readBooks()
 stu.doHomework()
 }
}

lambda表达式如下

fun doStudy(study: Study?) {
 study?.let {
 it.readBooks()
 it.doHomework()
 }
}

4.8:字符串内嵌表达式

val brand = "Samsung"
val price = 1299.99
println("Cellphone(brand=" + brand + ", price=" + price + ")")

使用内嵌表达式如下

val brand = "Samsung"
val price = 1299.99
println("Cellphone(brand=$brand, price=$price)")

同样也可以使用如下${函数}直接对函数进行拼接

 println("lambda表达式高阶函数返回的数据是${resultMinus}")
 val resultMinus = num1AndNum2(num1, num2) { n1, n2 ->
        n1 - n2
    }

4.9:函数的默认表达式

表示一个函数的参数允许存在默认值 这样我们调用的时候可以不传已经存在的值,默认调用默认存在的值

fun printParams(num: Int, str: String = "hello") {
 println("num is $num , str is $str")
}
fun main() {
 printParams(123)
}
//也可以使用键值对匹配的方式添加数据,意思就是可以不按照函数中的参数排列方式进行传参,只要键值对对应就可以
printParams(str = "world", num = 123)

好了关于变量和函数相关的知识告一段落下一篇文章我会输出关于Kotlin的标准函数和静态方法等相关知识~ 点赞加关注!学习不迷路!😬😬😬😬😬😬😬😬😬😬 有什么问题欢迎留言指出😜😜😜😜😜😜😜😜😜😜