Kotlin 基础(二)

162 阅读9分钟
  • 什么是匿名函数

    • 没有名字的;直接就给出了函数体
  • account的使用

    • count{},包裹的部分就是匿名函数(这个匿名函数就只有一条语句:it == 'r')
     fun main(){
         val len = "WAsbry".count()
         println(len)//6
         
         val len1 = "WAsbry".count{
             //it等于W A s b r y中的每一个字符
             it == 'r'//这一句就是匿名函数
         }
         println(len1)//出来1
     }
    
  • Kotlin函数拆解与隐式返回

    • 概述:

      • 函数拆解:将一个完整的函数定义拆成声明与实现两个部分
      • 隐式返回:Kotlin中的匿名函数的最后一行就是其返回值
    • 用处:可以在函数A中定义函数B

    • 拆解步骤

      • 定义函数的输入输出声明
      • 定义函数的实现
    • 细节:

      • 匿名函数的返回值在声明处就已经定义好了
      • 匿名函数中不要写return语句,匿名函数的最后一行就是其返回值
     fun main(){
         //定义函数输入输出的声明 :表示后接函数输入/出 ()为函数输入   -> 为函数输出
         val methodAction : () -> String
         //第二步:对函数的实现
         methodAction = {
             val inputValue = 999    
             "$inputValue WAsbry"
             //88,这样子就要报错,因为kotlin中的匿名函数的最后一行就是此函数的返回值(并且在函数声明的时候就指定了这个匿名函数的返回值是String)--->会造成类型对不上
         }
         //第三步:调用此函数
         println(methodAction())//打印出999 WAsbry
     }
    
  • Kotlin 函数参数进阶版本

    • 概述:

      • 在函数声明的时候,指定形参类型(可以不要具体变量),指定返回值,将声明与实现使用=进行连接
      • 在函数实现体(匿名函数)中指定具体变量用于承接函数参数
      • 匿名函数的最后一行为其返回值,不要在匿名函数中写return语句
     fun main(){
         //函数声明与实现
         val methodAction : (Int,Int,Int) -> String={number1,number2,number3 ->
             val inputValue=999
             "$inputValue Wasbry 参数一:$number1,参数二:$number2,参数三:$number3"
         }
         //函数的调用
         println(methodAction(1,2,3))
     }
     //上面的那个(除了函数调用)等效于下面这个
     fun methodAction(number1: Int,number2: Int,number3:Int): String{
         val inputValue = 999
         return "$inputValue WAsbry 参数一:$number1,参数二:$number2,参数三:$number3"
     }
    
  • it 关键字

    • 场景

      • 当函数只有一个参数的时候,kotlin会在函数体中内置一个it,作为这个参数的指代
    • 实现细节

      • 当函数形参是Double,实参也要是Double,不能传int值;
      • 在这个kotlin 里面好像没得关于函数参数的自动类型转化
      • 有两个及以上的函数参数就没有 it 了
     fun main(){
         //对于这种只有一个参数的匿名函数来说,仅需指定形参类型不需要搞一个具体形参属性
         val methodAction2 : (String) -> String = {"$it WAsbry"}//函数的声明与实现
         //函数的调用,打印它的返回值
         println(methodAction2("parm"))//打印出:parm WAsbry
     }
     //跟上面那个等价,这个it是被隐藏了的
     fun methodAction2(it: String) : String{return "$it WAsbry"}
    
  • 匿名函数的类型推断

    • 概述:匿名函数的返回值是不用显示指明的(可以自动推断的)

    • 实现细节

      • 当函数名后接冒号,必须制定参数类型与返回类型

         fun main(){
             val method1 : (String)->String = {}
         }
        
      • 当函数名后接等号,函数体(匿名函数中)最后一行就是函数的返回值

        • 不用显示指定函数参数类型

           //不指定函数参数类型,此时函数的返回值为浮点数
           fun main(){
               val method3 = {
                   345.3f
               }
           }
          
        • 不用显示指定函数返回值类型

           fun main(){
                               //这三个是传入的参数
               val method2 = {v1:Double,v2:Float,v3:Int ->
                   555//作为匿名函数的最后一行,那么这个函数的返回值就是Int
                   ""//作为匿名函数的最后一行,此时函数的返回值类型为String
                   true//Boolean
                   3.14f//Float
               }
               //匿名函数调用
               println(method2(3.14,2.68f,666))
           }
          
  • Lamda学习

    • 概述:

      • 括号就是一个匿名函数
      • 匿名函数就是lamda,他们是等价的,只是名字不一样而已
    • 实现两数相加

       fun main(){
           val addResultMethod = {number1: Int,number2: Int ->
               "两数相加的结果是:${number1 + number2}"    
           }
       }
      
    • 匿名函数的返回值类型(多种返回值类型可能--->就返回Any类型)

       fun main(){
           //匿名函数 入参Int,           返回类型Any(因为有可能有多种返回值类型)
           //Lamda表达式的参数Int,       Lamda表达式的结果为Any类型
           val weekResultMethod = { number: Int
               when(number){
                   1 -> "星期一"
                   2 -> "星期二"
                   3 -> "星期三"
                   else -> -1
               }//注意,这个when整体算作一条语句,在匿名函数中默认使用函数体内最后一条语句作为函数的返回值
           }
           println(weekResultMethod(2))//打印出"星期二"
       }
      
  • 函数作为函数参数

    • 概述:

      • Java中使用接口
      • Kotlin 直接哪一个Lamda作为函数的参数,进行处理
    • 应用

      • 模拟数据库登录
    • 实现细节

    • 在java中作值判断,采用equals,但是在kotlin中可以直接采用 ==

    • java 中的 if 是一条语句,而kotlin中的 if 是一个表达式(具有返回值)

    • kotlin中的字符串模板,可以作为java中的String.format(Kotlin 中的字符串模板)

    • 在kotlin中同一个package下的类中都不能有重名的方法

      • 在查看kotlin的java版本的时候发现,kotlin中的函数在转换为java的方法的时候,会在前面加上public static void
-   代码示例(kotlin版本)
    ```
     /**
      * 使用Lamda表达式作为函数参数,可以写在函数参数列表里面,也可以写在外面;
      * */
     fun main(){
         //第一种实现方式,函数原型的参数三是一个Lamda(匿名函数),
         loginAPI("WAsbry","1008611",{msg: String,code: Int ->
             println("最终登录的情况如下:msg:$msg,code:$code")
         })
         //第二种实现方式
         loginAPI("WAsbry","1008611",responseResult = {msg: String,code:Int ->
             println("最终登录的情况如下:msg:$msg,code:$code")
         })
         //第三种实现方式
         loginAPI("WAsbry","1008611"){msg: String,code:Int ->
             println("最终登录的情况如下:msg:$msg,code:$code")
         }
     }
     ​
     //模拟数据库SQLSever
     const val USER_NAME_SAVE_DB="WAsbry";
     const val USER_PWD_SAVE_DB="1008611";
     ​
     //登录API,模仿前端操作
     //采用Lamda表达式:responseResult:(String,Int)->Unit来代替接口
     fun loginAPI(username: String,userpassword: String,responseResult: (String,Int)->Unit){
         if(username == null || userpassword == null){
             TODO("用户名或者密码为空")//程序发现异常,终止
         }
         //做校验工作,前段校验
         if(username.length>3 && userpassword.length>3){
             if (webServiceLoginAPI(username,userpassword)){
                 //登录成功
                 //可以做一些其他的事情,比如说校验成功信息等
                 responseResult("login success",200)
             }else{
                 //登录失败的逻辑处理
                 responseResult("login error",444)
             }
         }else{
             TODO("用户名或密码不规范,请检查输入")
         }
     }
     ​
     //登录API暴露者,服务器
     private fun webServiceLoginAPI(name: String,pwd: String):Boolean{
         //Kotlin中的 if 是表达式,这玩意儿是可以有返回值的
         return if(name==USER_NAME_SAVE_DB && pwd==USER_PWD_SAVE_DB) true else false
     }
    ```

-   代码示例(java版本)

    ```
     package Kotlin;
     ​
     interface ResponseResult{
         void result(String msg,int code);
     }
     public class Test {
        public static final String USER_NAME_SAVE_DB="WAsbry";
         public static final String USER_PWD_SAVE_DB = "1008611";
         public static void main(String[] args) {
             //第一种实现方式,函数原型的参数三是一个Lamda(匿名函数),
             loginAPI("WAsbry", "1008611", new ResponseResult() {
                 @Override
                 public void result(String msg, int code) {
                     System.out.println(String.format("最终登录的情况如下:msg:%s,code:%d",msg,code));
                 }
             });
         }
         public static void loginAPI(String username,String userpassword,ResponseResult responseResult){
             if(username == null || userpassword == null){
     //            TODO("用户名或者密码为空")//程序发现异常,终止
             }
             //做校验工作,前段校验
             if(username.length()>3 && userpassword.length()>3){
                 if (webServiceLoginAPI(username,userpassword)){
                     //登录成功
                     //可以做一些其他的事情,比如说校验成功信息等
                     responseResult.result("login success",200);
                 }else{
                     //登录失败的逻辑处理
                     responseResult.result("login error",444);
                 }
             }else{
     //            TODO("用户名或密码不规范,请检查输入")
             }
         }
     ​
     //登录API暴露者,服务器
     private static boolean webServiceLoginAPI(String name,String pwd){
             //Kotlin中的 if 是表达式,这玩意儿是可以有返回值的
             if(name==USER_NAME_SAVE_DB && pwd==USER_PWD_SAVE_DB)
                 return true;
             else
                 return false;
             }
     }
    ```
  • 简化版本

    • 概述:Lamda 表达式可以写在外面也可以写在里面

           //第一种实现方式,函数原型的参数三是一个Lamda(匿名函数),
           loginAPI("WAsbry","1008611",{msg: String,code: Int ->
               println("最终登录的情况如下:msg:$msg,code:$code")
           })
           //第二种实现方式
           loginAPI("WAsbry","1008611",responseResult = {msg: String,code:Int ->
               println("最终登录的情况如下:msg:$msg,code:$code")
           })
           //第三种实现方式
           loginAPI("WAsbry","1008611"){msg: String,code:Int ->
               println("最终登录的情况如下:msg:$msg,code:$code")
           }
      
  • Kotlin中的内联

    • 当函数参数含有Lamda项,尽量在函数前面使用inline关键词,这样做,会在调用处做代码替换处理,类似于C++中的宏定义;进而减少函数开辟,对象开辟,函数调用,对象调用
     import webServiceLoginAPI as webServiceLoginAPI1
     ​
     /**
      * 使用Lamda表达式作为函数参数
      * */
     fun main(){
         loginAPI("WAsbry","1008611"){msg: String,code:Int ->
             println("最终登录的情况如下:msg:$msg,code:$code")
         }
     }
     ​
     //模拟数据库SQLSever
     const val USER_NAME_SAVE_DB="WAsbry";
     const val USER_PWD_SAVE_DB="1008611";
     //采用Lamda表达式来代替接口
     //此函数中有Lamda参数,使用内联,
     //如果说,不适用内联,在调用端会生成多个对象来完成Lamda的调用(造成性能损耗),这个在字节码里面就能看到
     //内联类似于C++中的define,编译期间将代码替换到调用处,那么在调用出原始的对象创建,调用等都没得了,快
     ​
     inline fun  loginAPI(username: String,userpassword: String,responseResult: (String,Int)->Unit){
         if(username == null || userpassword == null){
             TODO("用户名或者密码为空")//程序发现异常,终止
         }
         //做校验工作,前段校验
         if(username.length>3 && userpassword.length>3){
             if (webServiceLoginAPI1(username,userpassword)
             ){
                 //登录成功
                 //校验成功
                 responseResult("login success",200)
             }else{
                 //登录失败的逻辑处理
                 responseResult("login error",444)
             }
         }else{
             TODO("用户名或密码不规范,请检查输入")
         }
     }
     //次函数没有使用Lamda作为参数,那么久不要声明为内联
     //登录API暴露者,服务器
     private fun webServiceLoginAPI(name: String,pwd: String):Boolean{
         //Kotlin中的 if 是表达式,这玩意儿是可以有返回值的
         return if(name==USER_NAME_SAVE_DB && pwd==USER_PWD_SAVE_DB) true else false
     }
    
  • Kotlin 中的函数引用

    • 概述:

      • Lamda是函数类型的对象
      • 内联 (inline,配合 :: 进行使用)就可以将一个普通函数变成函数类型的对象
      • 函数引用可以将函数作为一个参数进行传入
    • 应用场景:

      • 函数A参数为Lamda表达式,
    • 使用方法:

      • 将Lamda表达式的实现抽象为一个函数B
      • 在函数A前,加上内联符号inline
      • 在调用函数A的时候,将参数Lamda,使用 ::B 进行替换
    • 好处:

      • 提升性能
    • 实现细节:

      • 也可以将函数引用封装为一个变量,作为函数参数
    • 代码示例:

     /**
      * 使用Lamda表达式作为函数参数
      * */
     fun main(){
         //函数引用,第三个为函数对象,将普通类型变成函数引用,Lamda的调用
         login("WAsbry","1008611",::methodResponseResult)
         val obj=::methodResponseResult
         val obj2=obj
         val obj3=obj2
         //这样子也是可以调用的
         login("WAsbry","1008611",obj3)
     }
     ​
     //Lamda的实现
     fun methodResponseResult(msg: String,code: Int){
         println("最终登录结果:msg:$msg,code:$code")
     }
     ​
     //模拟数据库SQLSever
     const val USER_NAME_SAVE_DB="WAsbry";
     const val USER_PWD_SAVE_DB="1008611";
     //这里的第三个参数是Lamda的声明
     inline fun login(name: String,pwd: String,responseResult: (String,Int)->Unit){
         if (USER_NAME_SAVE_DB == name && USER_PWD_SAVE_DB == pwd){
             //登录成功,书写相应的逻辑
             responseResult("登陆成功",200)
         }else{
             //登录失败,书写相应的逻辑
             responseResult("登录失败",404)
         }
     }
     ​
    
  • 函数类型作为返回类型(在函数中返回一个函数)

    • 概述:

      • 匿名函数B作为函数A的返回类型
      • Java是做不到的
    • 实现细节:

      • 需要在函数的声明处指定好匿名函数的规则
     fun main(){
         show("Hello World")
         val fake_show=showMethod("fake")
         //这里就证明了,第三行的返回值是一个函数,因为这个返回值是可以调用的
         fake_show("WAsbry",20)//打印出 我就是匿名函数:我的name:WAsbry,age:20  
     }
     ​
     fun show(info: String):Boolean{
         println("这里是show函数,info:$info")
         return true
     }
     fun show2(info: String):String{
         println("这里是show函数")
         return "DDD"
     }
     //14行,显示指明了这个函数是返回一个函数类型的变量,入参是String,Int,返回值为String
     fun showMethod(info: String):(String,Int)->String{
         println("这是show函数 info:$info")
         //return 一个匿名函数
         return {
             name:String,age:Int->
             "我就是匿名函数:我的name:$name,age:$age"
         }
     }
    
  • Kotlin 中的具名函数

    • Lamda是函数对象级别的,对照着函数引用,普通的函数需要转成函数引用才能匹配
     //lamda表达式的本质是函数对象级别的,那么需要将普通函数转变为函数对象级别的才能去对标Lamda
     fun main(){
         //匿名函数
         showPersonInfo("lisi",99,'男',"Hello Kotlin"){
             println("显示结果:$it")
         }//这括号及其里面的代码就是匿名函数,也叫Lamda的实现体
         //具名函数showResultIml
         showPersonInfo("wang",99,'女',"Hello Java",::showResultIml)
     }
     ​
     fun showResultIml(result: String){
         println("显示结果:$result")
     }
     ​
     inline fun showPersonInfo(name:String,age:Int,sex:Char,study:String,showResult:(String)->Unit){
         val str="name:$name,age:$age,sex:$sex,study:$study"
         showResult(str)
     }
    

    java版本:需要使用接口的这种折中的方案来实现kotlin中的Lamda表达式效果

     package Kotlin;
     ​
     interface IsShowResult{
         void result(String result);
     }
     public class Test {
         public static void main(String[] args) {
             //匿名函数 -> 匿名接口实现
             showPersonInfo("lisi", 99, 'm', "study kotlin", new IsShowResult() {
                 @Override
                 public void result(String result) {
                     System.out.println("显示结果: "+result);
                 }
             });
             //具名函数 具名接口实现showResultIml
             IsShowResult showResultIml = new MshowResultIml();
             showPersonInfo("wangwu",88,'n',"study kotlin",showResultIml);
         }
         static class MshowResultIml implements IsShowResult{
             @Override
             public void result(String result) {
     ​
             }
         }
         static void  showPersonInfo (String name,int age,char sex,String study,IsShowResult isShowResult) {
             String str= String.format("name:$name,age:$age,sex:$sex,study:$study");
             isShowResult.result(str);
         }
     }