Kotlin函数

  1. 函数头
  2. 函数参数
    (1)默认值参数
    (2)具名函数参数
  3. Unit函数
  4. Nothing函数
  5. 反引号中的函数名
  6. 匿名函数
    (1)匿名函数与隐式返回
    (2)匿名函数参数
    (3)it关键字
    (4)匿名函数类型推断
    (5)lambda表达式
    (6)定义参数是函数的函数
    (7)函数内联
    (8)函数引用
    (9)函数作为返回类型
    (10)闭包
    (11)lambda与匿名内部类
  7. 基本函数
    (1)subString
    (2)split
    (3)replace
    (4)== 与 ===
    (5)for each
    (6)数字类型
    (7)安全转换函数
    (8)Double转Int,Double类型格式化
  8. 标准函数库
    (1)apply
    (2)let
    (3)run
    (4)with
    (5)also
    (6)takeIf
    (7)takeUnless

1.函数头

定义函数方法的基本形式
在这里插入图片描述
2.函数参数
(1)默认值参数
参数带有默认值时,可以省略参数

但是当默认值参数不在第一个时,需要指定参数名才能省略参数

在这里插入图片描述

(2)具名函数参数
在这里插入图片描述
3. Unit函数
当函数没有返回值时即用Unit,由于优秀的类型推断机制,Unit可以省略不写
在这里插入图片描述

当lambda表达式没有必须写Unit

在这里插入图片描述
4.Nothing类型
TODO函数的作用就是抛出异常
Nothing类型返回值永远为空

5.反引号中的函数名

在Java类中创建的类 如果Kotlin去调用,需要用··括起来
在这里插入图片描述
在这里插入图片描述
且可以用于创建一些花花的函数名

fun `**~special**`(){
    print("asd")
}

6.匿名函数

定义时不取名字的函数
匿名函数通常作为整体传递给其他函数,或者从其他函数返回
可以根据需要指定特殊规则,轻松定制标准库里的内置函数

(1)匿名函数与隐式返回

  • 匿名函数可以当做变量赋值给其他函数类型变量
  • 函数的类型由 传入的参数返回值类型 决定
  • 和具名函数不一样,除极少数情况外,匿名函数不需要return关键字返回数据,匿名函数会自动或隐式返回函数体最后一行语句的结果
    //变量的类型是一个匿名函数 传入参数 : 无参 -》 返回值是 : String类型
    val blessingFunction : ()->String
    //赋值
    blessingFunction = {
        val holiday = "New Yeay."
        //隐式或自动返回函数体最后一行语句的结果
        "Happy $holiday"
    }
    //函数类型的变量
    print(blessingFunction())

(2)匿名函数参数

  • 可以不带参数,也可以带一个、多个参数
  • 需要带参数时,参数的类型放在匿名函数的类型定义中,参数名则放在函数定义中
                            //参数类型              //参数名
    val blessingFunction2 : (String)-> String = { name ->
        val holiday = "New Year"
        "$it , Happy $holiday"
    }
    print(blessingFunction2("jack"))

(3)it关键字

  • 定义只有一个参数的匿名函数时,可以用it关键字来表示参数名
  • 定义多个参数时,it关键字就没有用了
                            //参数类型              //参数名
    val blessingFunction2 : (String)-> String = { it ->
        val holiday = "New Year"
        "$it , Happy $holiday"
    }

    print(blessingFunction2("jack"))

(4)匿名函数类型推断
优秀的类型推断机制可以不用在函数参数申明位置写函数参数
但是必须要函数名后加参数类型(并没有优化)

    val blessingFunction3 = { name : String, age : Int ->
        val holiday = "New Year"
        "$name is $age years old,Happy $holiday"
    }

我还是比较喜欢这样写

    val blessingFunction3 : (String,Int) -> String = { name , age  ->
        val holiday = "New Year"
        "$name is $age years old,Happy $holiday"
    }

(5)lambda表达式

  • 匿名函数即为lambda
  • 匿名函数的定义为lambda表达式
  • 匿名函数返回结果即为lambda结果

(6)定义参数是函数的函数

//具名函数
fun showOnBoard(goodsNmae : String,getDisCountWordss : (String,Int) -> String){
    //shuffled()打乱顺序
    //last()取最后一个
    val hour = (1..24).shuffled().last();
    println(getDisCountWordss(goodsNmae,hour))
}
    val aaa = { goodsName : String,houe : Int ->
        val currendYear = 2021
        //$currendYear年   -> 会报错 需要空格
        //$currendYear 年  -> 打印出来会出一个空格
        //${currendYear}年 -> 不会报错也不会多打印空格
        "${currendYear}年,双11${goodsName}促销倒计时: ${houe}小时"
    }

    showOnBoard("卫生纸",aaa)

也可以直接将lambda表达式作为函数参数

    showOnBoard("卫生纸",{ goodsName : String,houe : Int ->
        val currendYear = 2021
        "${currendYear}年,双11${goodsName}促销倒计时: ${houe}小时"
    })

简化 ->
如果一个函数的lambda参数排在最后,或者是唯一的参数,那么括住lambda值参的一对圆括号就可以省略

    showOnBoard("卫生纸"){ goodsName : String,houe : Int ->
        val currendYear = 2021
        "${currendYear}年,双11${goodsName}促销倒计时: ${houe}小时"
    }

(7)函数内联
问题:
在JVM上,定义的lambda会以对象实例的形式存在,JVM会为所有同lambda打交道的变量分配内存,产生内存开销,带来严重的性能问题
解决:
函数内联,JVM就不需要使用lambda对象实例,避免变量内存分配,哪里需要lambda,编译器就会将函数体复制粘贴到哪里

使用lambda的递归函数无法内联
inline fun showOnBoard(goodsNmae : String,getDisCountWordss : (String,Int) -> String){
    //shuffled()打乱顺序
    //last()取最后一个
    val hour = (1..24).shuffled().last();
    println(getDisCountWordss(goodsNmae,hour))
}

(8)函数引用
要把函数作为参数传递给其他函数使用,除了传递lambda表达式,还可以传递函数引用,函数引用可以把一个具名函数转换成一个值参

使用lambda表达式的地方都可以使用函数引用
fun main() {
    showOnBoard2("牙膏",::getDiscountName2)
}

fun getDiscountName2(goodsNmae: String,hour : Int) : String {
    //shuffled()打乱顺序
    //last()取最后一个
    val currendYear = 2077;
    return "${currendYear}年,双11${goodsNmae}促销倒计时: ${hour}小时"
}

//具名函数
fun showOnBoard2(goodsNmae : String,hanshu : (String,Int) -> String){
    val hour = (1..24).random();
    println(hanshu(goodsNmae,hour))
}
::引用函数

(9)函数作为返回类型

fun main() {

    val configDiscountWords = configDiscountWords()
    print(configDiscountWords("沐浴露"))
}

fun configDiscountWords() : (String) -> String {
    val currendYear = 2077
    val hour = (1..24).random()
    return {goodsName ->
        "${currendYear}年,双11${goodsName},促销倒计时: ${hour}小时"
    }
}

(10)闭包

  • 在kotlin中,匿名函数可以修改并引用定义在自己的作用域之外的变量,匿名函数引用着定义自身的函数里的变量

  • 能接受函数或者返回函数的函数叫做高级函数,高级函数广泛应用于函数式编程当中

     Kotlin中的lambda表达式就是闭包
    
fun configDiscountWords() : (String) -> String {
    val currendYear = 2077
    val hour = (1..24).random()
    return {goodsName ->
        "${currendYear}年,双11${goodsName},促销倒计时: ${hour}小时"
    }
}

(11)lambda与匿名内部类

在java中,如果要传递函数

  1. 创建接口
  2. 实现匿名内部类 -> 或者实现接口,并将接口对象传入
    public static void main(String[] args) {
        showOnBoard("牙膏", new DiscountWords() {
            @Override
            public String getDiscountWords(String goodsName, int hour) {
                return goodsName + hour + goodsName;
            }
        });
    }
    //接口
    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));
    }

Kotlin匿名内部类

fun main() {

    //  变量名  变量类型是函数           赋值
    val aaa : (goodsName : String,hour : Int) -> String = {goodsName,hour ->
        val cur = 2021
        "${cur}年,双11${goodsName}商品促销倒计时${hour}小时"
    }
    showOnBoard3("袜子",aaa);
    println("")
    print("___________")
    println("")
    showOnBoard3("洗发水",{goodsName : String,hour : Int ->
        val cur = 2021
        "${cur}年,双11${goodsName}商品促销倒计时${hour}小时"
    })

    println("")
    print("___________")
    println("")
    showOnBoard3("沐浴露"){goodsName : String,hour : Int ->
        val cur = 2021
        "${cur}年,双11${goodsName}商品促销倒计时${hour}小时"
    }


}
//                       参数1 是String                    参数2 是lambda表达式
private fun showOnBoard3(goodsName : String,getDiscouns : (String,Int) -> String) : Unit{
    val hour = (1..24).random()
    print(getDiscouns(goodsName,hour))
}

7.基本函数
(1)subString
java

const val NAME = "Jimmy's friend"

    val indexOf = NAME.indexOf('\'')
    val str = NAME.substring(0,indexOf)

Kotlin

    val str2 = NAME.substring(0 until indexOf)

(2)split
split函数返回的是List集合,List集合又支持解构语法特性,它允许在一个表达式里给多个变量赋值,解构常用来简化变量赋值

const val NAMES = "Jack,Ross,Jason"

    val split : List<String> = NAMES.split(',')

    val(origin : String,dest : String,proxy : String) = NAMES.split(',')
    println("${origin},${dest},${proxy}")

(3)replace

    val str3 = "The people's public og China"
    val str4 = str3.replace(Regex("[aeiou]")){
        when(it.value){
            "a" -> "8"
            "e" -> "6"
            "i" -> "9"
            "o" -> "1"
            "u" -> "3"
            else -> it.value
        }
    }

(4)== 与 ===
在kotlin中
用 == 比较来比较两个字符串是否匹配
用 === 来比较 两个变量是否指向内存堆上同一对象
在Java中
用 == 做引用比较
用equals方法作结构

    val str = "Jason"
    val str2 = "Jason"
    val str3 = "jason".capitalize()

    //比较内容
    println(str == str2)
    //比较对象
    //字符串常量池 字符串是不可变的
    println(str === str2) //true
    println(str === str3) //false

(5)for each

    val str3 = "The people's public og China"
    str3.forEach {
        println("$it *")
    }

(6)数字类型

图片

(7)安全转换函数
Kotlin提供了toDoubleOrNull 和 toIntOrNull这样的安全转换函数
如果数值不能正确转换
与其触发异常还不如返回null

//    val number : Int = "8.98".toInt() fasle
        val number : Int? = "8.98".toIntOrNull()  //null

(8)Double转Int,Double类型格式化

    println(8.95256.toInt())        //8
    println(8.95256.roundToInt())   //9 四舍五入
    "%.2f".format(8.95756)   //8.96 保留两位小数 四舍五入

8.标准函数库
(1)apply

apply函数可以看作是一个配置函数,可以传入一个接收者
然后调用一系列函数来配置它
如果提供lambda表达式,会返回配置好的接收者
    val file1 = File("C:\\Users\\10185\\Desktop\\a.txt");
    file1.setReadable(true)
    file1.setWritable(true)
    file1.setExecutable(false)
    
    //                                                                      this 隐式调用
    val file2 = File("C:\\Users\\10185\\Desktop\\a.txt").apply { 
        setReadable(true)
        setWritable(true)
        setExecutable(false)
        //返回file2对象
    }

(2)let

let函数能是某个变量作用于其lambda表达式里,让it关键字能引用它

let与apply比较
(1)let会把接收者传递给lambda,apply什么都不传
(2)let返回lambda表达式最后一行,apply返回当前接收者
fun main() {
    //使用let
    val let = listOf<Int>(3, 2, 1).first().let {
        //返回最后一行
        it * it
    }
    println(let)
    //不用let
    val last = listOf<Int>(3, 2, 1).last()
    val last2 = last * last
    
    //使用let
    formatGreaeting(null);
    formatGreaeting("jack");
    //不使用let
    formatGreaeting2(null)
    formatGreaeting2("ross")

}

fun formatGreaeting(guestName : String?) : String{
    return guestName?.let { 
        "Welcome $it"
    } ?: "what is your name"
}

fun formatGreaeting2(guestName : String?) : String{
    return if (guestName == null){
        "what is your name"
    }else{
        "Welcome ${guestName}"
    }
}

(3)run

作用域与apply差不多
但是与apply不同的是:run函数不返回接收者,*返回的是lambda结果*
->true、false、最后一行数据
    val file = File("C:\\Users\\10185\\Desktop\\a.txt")
    val result = file.run {
        //一次读完所有
        readText().contains("great")
        //返回true or false
    }
run可以 函数引用,相较于传统的方法是支持链式调用
fun main() {
    //                 链式调用
    "The People's Republic of China"
            //函数引用
        .run(::isLong)      //返回true
        .run(::showMessage) //返回字符串
        .run(::println)     //打印字符串

}

fun isLong(name : String) : Boolean{
    return name.length >= 10
}

fun showMessage(isLong : Boolean) : String{
    return if (isLong){
        "Name is to long"
    }else{
        "Please rename"
    }
}

(4)with

是run的变体,他们的功能行为是一样的
但with的调用方式不同,调用with时需要值参作为其第一个参数传入
    val run = "The People's Republic of China".run {
        length >= 10
    }
    val with = with("The People's Republic of China") {
        length >= 10
    }

(5)also

also和let功能相似
和let一样,also也是把接收者作为值参传给lambda
但是有一点不同:
also返回接收者对象,let返回lambda结果
因为这个差异,also尤其适合针对同一原始对象,利用其副作用做事
既然返回的是接收者,就可以*基于原始接收者对象执行额外的链式调用*
    var fileContents:List<String>

    //返回接收对象
    val also : File = File("C:\\Users\\10185\\Desktop\\a.txt")
        .also {
            print(it.name)
        }.also {
            fileContents = it.readLines()
        }

    //返回执行结果
    val let : String = File("C:\\Users\\10185\\Desktop\\a.txt").let {
        fileContents = it.readLines()
        it.name
    }

(6)takeIf

takeIf需要传入一个接收者
takeIf函数需要判断lambda中提供的表达式,给出true、false的结果
如果判断结果是true	->返回接收者对象
如果判断结果是false->返回null
如果需要判断某个条件是否满足,再决定是否可以赋值变量或执行某项任务,takeIf就很有用
    val readText = File("C:\\Users\\10185\\Desktop\\a.txt")
        .takeIf {
            it.exists() && it.canRead()
        }?.readText()

    println(readText)
    //不使用takeIf
    val file = File("C:\\Users\\10185\\Desktop\\a.txt")
    if(file.exists() && file.canRead()){
        println(file.readText())
    }else{
        print(null)
    }

(7)takeUnless

与takeIf相反
    val readText = File("C:\\Users\\10185\\Desktop\\a.txt")
        .takeUnless { 
            it.isHidden
        }?.readText()
    
    println(readText)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值