Kotlin语言

Android Kotlin语法

Kotlin与JVM

在这里插入图片描述

Kotlin 语言的跨平台特性

在这里插入图片描述

Kotlin语法

1、快速了解Kotlin
Hello Kotlin
fun main() {
    println("Hello world") // 输出:Hello world

    //声明变量
    var hello : String = "Hello"
    var world = "world"
    //以及字符串拼接
    println("$hello $world") // 输出:Hello world

    //内置数据类型
    /*
        String  字符串
        Char    单字符
        Boolean true/false
        Int     整型
        Double  小数
        List    集合
        Set     无重复集合
        Map     键值对集合
     */
}
var 与 val

val 只读变量
var 可写可读的变量

fun main() {
    // val 只读不能修改
    val info : String = "info"
    // info = "new info" --> 这段代码会报错

    // var 可以修改
    var info2 : Int = 1
    println(info2) // 输出 1
    info2 = 2
    println(info2) // 输出 2
}
类型推导

Kotlin会类型推导
根据赋值时的类型,给变量定义对应的类型

fun main() {
    // 根据赋值时的类型,给变量定义对应的类型
    val info : String = "info"
    // ": Stirng" 是可以不用写的
    val info2 = "info"

    // 同理
    val age : Int = 10
    val age2 = 10

    // 同理
    val flag : Boolean = false
    val flag2 = false
}
编译时常量 const
// const 是编译时常量
// 编译时常量只能在函数之外定义,编译期间初始化
const val A = 10

fun main() {
    // const 用于定义常量
    // const val A = 10 报错提示:const不适用于局部变量

    val info = A // val是只读变量
    println(info) // 输出 10
}
查看Kotlin反编译后字节码

编译器的 Tool - Kotlin - Show Kotlin BtyeCode可以查看Kotlin的字节码。
在这里插入图片描述
因为Kotlin要运行在JVM上所以它的字节码就是Java的字节码。

Java字节码转Java代码
在这里插入图片描述

引用类型

Kotlin的引用类型,都是Kotlin实现的类型
如: Int \ Float \ Double \ Boolean
它们最终都会转换成java的基础类型。
在这里插入图片描述
转化成java后
在这里插入图片描述

rane表达式
fun main() {
    val number = 100

    if(number in 10..50){
        println("在 10 到 50 以内,闭包的")
    }else if(number in 100..1000){
        println("在 100 到 1000 以内,闭包的")
    }else if(number in 0..100){
        println("在 0 到 100以内,闭包的")
    }
    
    // 输出结果: 在 100 到 1000 以内,闭包的
}
when表达式

在 Kotlin 中 if 和 when 都是表达式,是有返回值的

fun main() {
    var week = 5

    // 在 Kotlin 中 if 和 when 都是表达式,是有返回值的
    var info = when(week){
        1 -> "1111111"
        2 -> "2222222"
        3 -> "3333333"
        4 -> "4444444"
        5 -> "5555555"
        else -> {
            println("other")
        }
    }
    println("info : $info") // info : 5555555

    week = 7
    info = when(week){
        1 -> "1111111"
        2 -> "2222222"
        3 -> "3333333"
        4 -> "4444444"
        5 -> "5555555"
        else -> {
            "other"
        }
    }

    println("info : $info") // info : other
}
String模板
fun main() {
    val name = "name"
    val count = 10

    println("name:$namecount:$count") // 报错!!,因为她会识别“namecount”为一起的,但是又没有这个变量
    println("name:$name count:$count") // 加个空格隔开就不会了
    println("name:${name}count:$count") //如果就是需要贴在一起的,可以将变量包裹在{}里

    val flag = true
    // 还可以用when或者if填充在里面,因为Kotlin里面if和when属于表达式,而java是语句
    // 也就是说Kotlin的整个if语句或when语句可以当作为一个方法函数
    println("name? ${if(flag)"true" else "false"}")
}
函数
/*
 修饰符 函数关键字 函数名(参数名:参数类型) :返回类型
 */
private fun method01(age:Int, name:String) : Int{
    println("age $age namne $name")
    return 100
}
函数默认参数
fun main() {
    method01(20,"Kotlin") // 输出 age 20 namne Kotlin
    // 不填写参数,会使用默认参数
    method01() // 输出 age 5 namne NON
}

/*
 函数的参数可以设置默认参数。
 */
private fun method01(age:Int = 5, name:String = "NON") : Int{
    println("age $age namne $name")
    return 100
}
具名参数函数参数
fun main() {
    //具名参数,可以随意调整参数的位置
    method01(name="Name2",age=10) // 输出 age 10 namne Name2
    //可以单独赋值其中某些参数
    method01(name="Name3") // 输出 age 5 namne Name3
}

private fun method01(age:Int = 5, name:String = "NON") : Int{
    println("age $age namne $name")
    return 100
}
Unit函数特点
// :Unit 可以不用写,相当于Java的void无返回
private fun method01(age:Int = 5, name:String = "NON") :Unit {
    println("age $age namne $name")
    return 100 //这句话会报错,因为定义函数无返回
}

private fun method02(age:Int = 5, name:String = "NON") {
    println("age $age namne $name")
}
Nothing类型特点
fun main() {
    method01(-1)
    // 运行报错
    // Exception in thread "main" kotlin.NotImplementedError: An operation is not implemented: 异常分数
    //	at MainKt.method01(Main.kt:8)
    //	at MainKt.main(Main.kt:2)
    //	at MainKt.main(Main.kt)
    
    // 因为TODO是一个会抛异常的代码,于Java的注解不一样
}


private fun method01(number: Int) {
    when(number){
        -1 -> TODO("异常分数")
        in 0..50 -> println("不及格")
        in 51..70 -> println("及格")
        in 71..100 -> println("优秀")
    }
}

Kotlin里面 TODO 的源码

/**
 * Always throws [NotImplementedError] stating that operation is not implemented.
 *
 * @param reason a string explaining why the implementation is missing.
 */
@kotlin.internal.InlineOnly
public inline fun TODO(reason: String): Nothing = throw NotImplementedError("An operation is not implemented: $reason")
反引号
fun main() {
    //中文也能定义
    测试方法_用于单元测试_编码人Pun()

    `is`(10)
}

private fun `测试方法_用于单元测试_编码人Pun`(){
    println("单元测试")
}

// is 不能作为函数名称,因为is是Kotlin的关键字
// 如果需要 is 的函数,可以加``
private fun `is`(count: Int){
    println("count $count")
}
2、Kotlin的函数
匿名函数
fun main() {
    val len = "name-hello".count()
    println(len) // 输出结果 : 10

    // 匿名函数
    // 以下这部分就是匿名函数部分,
    // { 
    //  it == 'l'
    // }
    val len2 = "name-hello".count{
        it == 'l'
    }
    println(len2) // 输出结果 : 2
}

为什么{it==‘l’}能让count函数只返回符合条件的字符数量呢?让我们看看count的源码

// 第一个函数,就是上面输出结果为 10所调用的方法。
@kotlin.internal.InlineOnly
public inline fun CharSequence.count(): Int {
    return length
}


/**
 * Returns the number of characters matching the given [predicate].
 */
 // 第二个函数,就是比较特别的函数
 // 1.它的参数是一个函数,而不是对象或值
 // 参数是一个函数,是Char作为参数Boolean值作为返回值的函数,就如同
 // {
 //    it == 'l'
 // }
public inline fun CharSequence.count(predicate: (Char) -> Boolean): Int {
    var count = 0
    // 遍历判断每个字符,匹配就+1,就是在计算我们指定字符的数量
    for (element in this) if (predicate(element)) ++count
    return count
}
函数类型于隐式返回
fun main() {
    // 第一步,函数输入输出的声明
    val methodAction : () -> String
    // 第二步:对上面函数的实现
    methodAction = {
        val i = 100
        // 它会以最后一行作为返回值
        "String $i" // 相当于 return "String " + i
    }

    // 第三步:调用函数
    println(methodAction()) // 输出结果 : String 100
}
函数参数
fun main() {
    // 第一步,函数输入输出的声明 // 第二步:对声明面函数的实现
    // 变量类型 函数名 : (参数类型) -> 返回值 = { 参数名 -> 
    //              函数体
    // {
    val methodAction : (Int,Int) -> String = { i1, i2 ->
        "String $i1 $i2"
    }

    println(methodAction(11,22)) // 输出 : String 11 22
}
it关键字
fun main() {
    // 单个参数函数会自带一个it作为参数
    val method : (String) -> String = {
        "String : $it"
    }

    println(method("443"))

    // 多个参数需要自己定义参数名
    // 以下代码会报错,因为没有写变量名,没有it参数
    val method2 : (String,Int) -> String = {
        "String : $it"
    }
}
函数的类型推断
fun main() {
    // 函数返回值类型的自动判断
    val obj = { number : Int ->
        when(number){
            1 -> "11111"
            2 -> 3.14f
            3 -> 100
            4 -> false
            5 -> MyClass()
            else -> Unit
        }
    }
    println(obj(1)) // 输出 : 11111
    println(obj(2)) // 输出 : 3.14
    println(obj(3)) // 输出 : 100
    println(obj(4)) // 输出 : false
    println(obj(5)) // 输出 : MyClass@7f690630
    println(obj(100)) // 输出 : kotlin.Unit
}

class MyClass{

}
函数中定义参数是函数的函数

类似于java的接口作为参数

fun main() {
    //将函数作为参数
    //一、匿名函数作为参数,三种写法
    loginApi("nono","1234") { msg: String,code: Int ->
        println("msg: $msg  code: $code")
    }
    //输出 msg: 登录失败  code: 200

    loginApi("nono","1234",{ msg: String,code: Int ->
        println("msg: $msg  code: $code")
    })
    //输出 msg: 登录失败  code: 200

    loginApi("nono","1234",response = { msg: String,code: Int ->
        println("msg: $msg  code: $code")
    })
    //输出 msg: 登录失败  code: 200

    //二、函数变量作为参数
    val response : (String, Int) -> Unit = { msg, code ->
        println("response --> msg: $msg code: $code")
    }
    loginApi("name","1234",response)
    //输出 response --> msg: 登录成功 code: 200
}

const val USER_NAME = "name"
const val USER_PWD = "1234"

fun loginApi(username: String,pwd: String, response: (String, Int) -> Unit){
    if (username == null || pwd == null){
        TODO("用户名或密码 null")
    }

    if (username == USER_NAME && pwd == USER_PWD){
        response("登录成功",200)
    }else{
        response("登录失败",200)
    }
}
函数内联

1、为什么使用内联
我们先有如下代码,没有使用内联:

fun main() {
    loginApi("nono","1234",response = { msg: String,code: Int ->
        println("msg: $msg  code: $code")
    })
    //输出 msg: 登录失败  code: 200
}

const val USER_NAME = "name"
const val USER_PWD = "1234"

fun loginApi(username: String,pwd: String, response: (String, Int) -> Unit){
    if (username == null || pwd == null){
        TODO("用户名或密码 null")
    }

    if (username == USER_NAME && pwd == USER_PWD){
        response("登录成功",200)
    }else{
        response("登录失败",200)
    }
}

将这块代码转换为java,留意代码中的注解

import kotlin.Metadata;
import kotlin.jvm.functions.Function2;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {1, 5, 1},
   k = 2,
   d1 = {"\u0000\u001e\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0002\b\u0003\n\u0002\u0018\u0002\n\u0002\u0010\b\n\u0002\b\u0002\u001a0\u0010\u0003\u001a\u00020\u00042\u0006\u0010\u0005\u001a\u00020\u00012\u0006\u0010\u0006\u001a\u00020\u00012\u0018\u0010\u0007\u001a\u0014\u0012\u0004\u0012\u00020\u0001\u0012\u0004\u0012\u00020\t\u0012\u0004\u0012\u00020\u00040\b\u001a\u0006\u0010\n\u001a\u00020\u0004\"\u000e\u0010\u0000\u001a\u00020\u0001X\u0086T¢\u0006\u0002\n\u0000\"\u000e\u0010\u0002\u001a\u00020\u0001X\u0086T¢\u0006\u0002\n\u0000¨\u0006\u000b"},
   d2 = {"USER_NAME", "", "USER_PWD", "loginApi", "", "username", "pwd", "response", "Lkotlin/Function2;", "", "main", "My_Kotlin_Application.app"}
)
public final class MainKt {
   @NotNull
   public static final String USER_NAME = "name";
   @NotNull
   public static final String USER_PWD = "1234";

   public static final void main() {
   		// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   		// 方法调用时,最后的lambda表达式会变成 一个 null.INSTANCE 
   		// 1、这里的null并不是问题所在,这个null猜测时因为解析不出来导致的
   		// 2、这里的null是一个对象,然后INSTANCE又是一个对象内部属性对象
   		// 3、当这个方法多次调用的时候,就会产生很多对象,占用资源
      loginApi("nono", "1234", (Function2)null.INSTANCE);
      loginApi("nono", "1234", (Function2)null.INSTANCE);
      loginApi("nono", "1234", (Function2)null.INSTANCE);
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }

   public static final void loginApi(@NotNull String username, @NotNull String pwd, @NotNull Function2 response) {
      Intrinsics.checkNotNullParameter(username, "username");
      Intrinsics.checkNotNullParameter(pwd, "pwd");
      Intrinsics.checkNotNullParameter(response, "response");
      if (Intrinsics.areEqual(username, "name") && Intrinsics.areEqual(pwd, "1234")) {
         response.invoke("登录成功", 200);
      } else {
         response.invoke("登录失败", 200);
      }

   }
}

以上java因为lambda表达式导致资源浪费问题

2、如何解决
在函数前添加 inline 关键字,启用内链

// 在函数强添加 inline 关键字
inline fun loginApi(username: String,pwd: String, response: (String, Int) -> Unit){
    if (username == null || pwd == null){
        TODO("用户名或密码 null")
    }

    if (username == USER_NAME && pwd == USER_PWD){
        response("登录成功",200)
    }else{
        response("登录失败",200)
    }
}

转换成java代码,会发现整个函数调用代码都不见了。
因为这个关键字实现了宏替换,将调用该函数的地方直接用函数的代码替换掉了

import kotlin.Metadata;
import kotlin.jvm.functions.Function2;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;

@Metadata(
   mv = {1, 5, 1},
   k = 2,
   d1 = {"\u0000\u001e\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0002\b\u0003\n\u0002\u0018\u0002\n\u0002\u0010\b\n\u0002\b\u0002\u001a6\u0010\u0003\u001a\u00020\u00042\u0006\u0010\u0005\u001a\u00020\u00012\u0006\u0010\u0006\u001a\u00020\u00012\u0018\u0010\u0007\u001a\u0014\u0012\u0004\u0012\u00020\u0001\u0012\u0004\u0012\u00020\t\u0012\u0004\u0012\u00020\u00040\bH\u0086\bø\u0001\u0000\u001a\u0006\u0010\n\u001a\u00020\u0004\"\u000e\u0010\u0000\u001a\u00020\u0001X\u0086T¢\u0006\u0002\n\u0000\"\u000e\u0010\u0002\u001a\u00020\u0001X\u0086T¢\u0006\u0002\n\u0000\u0082\u0002\u0007\n\u0005\b\u009920\u0001¨\u0006\u000b"},
   d2 = {"USER_NAME", "", "USER_PWD", "loginApi", "", "username", "pwd", "response", "Lkotlin/Function2;", "", "main", "My_Kotlin_Application.app"}
)
public final class MainKt {
   @NotNull
   public static final String USER_NAME = "name";
   @NotNull
   public static final String USER_PWD = "1234";

   public static final void main() {
      String username$iv = "nono";
      String pwd$iv = "1234";
      int $i$f$loginApi = false;
      short code;
      String msg;
      boolean var5;
      String var6;
      boolean var7;
      if (Intrinsics.areEqual(username$iv, "name") && Intrinsics.areEqual(pwd$iv, "1234")) {
         code = 200;
         msg = "登录成功";
         var5 = false;
         var6 = "msg: " + msg + "  code: " + code;
         var7 = false;
         System.out.println(var6);
      } else {
         code = 200;
         msg = "登录失败";
         var5 = false;
         var6 = "msg: " + msg + "  code: " + code;
         var7 = false;
         System.out.println(var6);
      }

      username$iv = "nono";
      pwd$iv = "1234";
      $i$f$loginApi = false;
      if (Intrinsics.areEqual(username$iv, "name") && Intrinsics.areEqual(pwd$iv, "1234")) {
         code = 200;
         msg = "登录成功";
         var5 = false;
         var6 = "msg: " + msg + "  code: " + code;
         var7 = false;
         System.out.println(var6);
      } else {
         code = 200;
         msg = "登录失败";
         var5 = false;
         var6 = "msg: " + msg + "  code: " + code;
         var7 = false;
         System.out.println(var6);
      }

      username$iv = "nono";
      pwd$iv = "1234";
      $i$f$loginApi = false;
      if (Intrinsics.areEqual(username$iv, "name") && Intrinsics.areEqual(pwd$iv, "1234")) {
         code = 200;
         msg = "登录成功";
         var5 = false;
         var6 = "msg: " + msg + "  code: " + code;
         var7 = false;
         System.out.println(var6);
      } else {
         code = 200;
         msg = "登录失败";
         var5 = false;
         var6 = "msg: " + msg + "  code: " + code;
         var7 = false;
         System.out.println(var6);
      }

   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }

   public static final void loginApi(@NotNull String username, @NotNull String pwd, @NotNull Function2 response) {
      int $i$f$loginApi = 0;
      Intrinsics.checkNotNullParameter(username, "username");
      Intrinsics.checkNotNullParameter(pwd, "pwd");
      Intrinsics.checkNotNullParameter(response, "response");
      if (Intrinsics.areEqual(username, "name") && Intrinsics.areEqual(pwd, "1234")) {
         response.invoke("登录成功", 200);
      } else {
         response.invoke("登录失败", 200);
      }

   }
}
函数引用
fun main() {
    // 普通的使用方式
    loginApi("nono","1234",response = { msg: String,code: Int ->
        println("msg: $msg  code: $code")
    })
    //输出 msg: 登录失败  code: 200

    // 函数引用
    loginApi("name","1234", ::myResponse)
    //输出 msg: 登录成功  code: 200

    val obj = ::myResponse
    loginApi("name","1234", obj)
    //输出 msg: 登录成功  code: 200
}

fun myResponse(msg: String, code: Int){
    println("msg: $msg  code: $code")
}

const val USER_NAME = "name"
const val USER_PWD = "1234"

inline fun loginApi(username: String,pwd: String, response: (String, Int) -> Unit){
    if (username == null || pwd == null){
        TODO("用户名或密码 null")
    }

    if (username == USER_NAME && pwd == USER_PWD){
        response("登录成功",200)
    }else{
        response("登录失败",200)
    }
}
函数类型作为返回类型
fun main() {
    val show = show("show")
    // 输出 show : show
    val show2 = show2("show2")
    // 输出 show2 : show2
    println(show2("name2",200))
    // 输出 name : name2, code : 200
}

// 普通函数,返回String类型
fun show(info: String) : Boolean{
    println(" show : $info")
    return true
}

// 函数,返回函数类型
fun show2(info: String) : (String, Int) -> String{
    println(" show2 : $info")

    return { name: String, code: Int ->
        "name : $name, code : $code"
    }
}
匿名函数于具名函数
fun main() {
    // 匿名函数
    show("info1"){
        println("it : $it")
    }
    // 输出 it : info1

    // 具名函数
    show("info2", ::myShowResult)
    // 输出 myShowResult : info2
}

fun myShowResult(info: String) : Unit{
    println("myShowResult : $info")
}

fun show(info: String, showResult:(String) -> Unit){
    showResult(info)
}

3、Kotlin与null
可空性特性
fun main() {
    var name : String = "name"
//    name = null // 提示不能赋值为 null,报错

    var name2 : String? = "name2"
    name2 = null
    println("name2 $name2")
    // 输出 name2 null
}
安全调用符
fun main() {
    var name : String? = "name"
    name = null

//    name.length // 报错,该变量可空类型,使用name需要有补救措施

    name?.length // 添加 ? 后,如果变量是null,后面的代码不会执行
    println("name : $name, size : ${name?.length}")
    // 输出 name : null, size : null
    name = "abc"
    println("name : $name, size : ${name?.length}")
    // 输出 name : abc, size : 3
}
let的安全调用
fun main() {
    var name : String? = null

    // 如果name为null,let逻辑不会执行
    name?.let {
        println("name $it, size : ${it.length}")
    }
    // 无输出

    name = "eee"
    name?.let {
        println("name $it, size : ${it.length}")
    }

    // 输出 name eee, size : 3
}
非空断言操作符
fun main() {
    var name : String? = null

    name!!.length // 不管 name 是不是 null 都会执行,null就抛异常
    // 输出
    // Exception in thread "main" java.lang.NullPointerException
    //	at MainKt.main(Main.kt:4)
    //	at MainKt.main(Main.kt)
}
空合并操作符
fun main() {
    var info : String? = ""
    info = null

    // 空合并操作符 对象 ?: 是null情况的操作
    println(info?:"is null")
    // 输出 is null

    // 与 let 关键字的组合用法
    var result = info?.let{
        "info is not null $it"
    } ?: "info is null"
    println(result)
    // 输出 info is not null
}
Kotlin先决条件函数
fun main() {
    var info : String? = null
    // checkNotNull(info)
    // 输出 Exception in thread "main" java.lang.IllegalStateException: Required value was null.
    //	at MainKt.main(Main.kt:3)
    //	at MainKt.main(Main.kt)

    // requireNotNull(info)
    // 输出 Exception in thread "main" java.lang.IllegalArgumentException: Required value was null.
    //	at MainKt.main(Main.kt:8)
    //	at MainKt.main(Main.kt)

    require(false)
    // 输出 Exception in thread "main" java.lang.IllegalArgumentException: Failed requirement.
    //	at MainKt.main(Main.kt:13)
    //	at MainKt.main(Main.kt)
}
4、Kotlin 与 字符串
substring
fun main() {
    val str = "hi hello"
    val indexOf = str.indexOf("e")
    // 输出 0 到 e 之间的内容
    println(str.substring(0,indexOf))
    // 输出 hi h
    
    // 输出 0 到 e 之间的内容
    println(str.substring(0 until indexOf))
    // 输出 hi h
}
split
fun main() {
    val str = "hi hello 你好"
    val list = str.split(" ")

    // 解构
    val (str1,str2,str3) = list
    println("str1 : $str1, str2 : $str2, str3 : $str3")

    // 当然你也可以遍历
    for (it in list){
        println("it $it")
    }
}
replace
fun main() {
    val str = "hi hello 你好"
    // 字符串.replace(Regex(要替换的内容,可用正则表达式)){
    //      替换后的字符串
    // }
    val str2 = str.replace(Regex("[a-z]")){
        when(it.value){
            "h" -> "A"
            "i" -> "B"
            "l" -> "C"
            else -> "?"
        }
    }

    println("str2 : $str2")
    // 输出 str2 : AB A?CC? 你好
}
== 与 ===
fun main() {
    // == 值 内容的比较
    // === 引用的比较
    val name1 = "name"
    val name2 = "name"

    println(name1 == name2)
    // 输出 true

    println(name1 === name2)
    // 输出 true
    // 因为有字符常量池,相同字符串引用指向都是同一个内存空间

    val name3 = StringBuffer("name").toString()
    println(name1 === name3)
    // 输出 false
    // 因为 StringBuffer 会开辟新的内存空间,所以两个字符串内存地址不一样

    println(name1 == name3)
    // 输出 true
    // 因为这里比较的是值,两个字符串都是 name 所以输出true

}
字符串遍历
fun main() {
    val str = "abcdefghijk"
    str.forEach {
        println(" it - $it")
    }
    // 遍历 输出 
    // it - a
    // it - b
    // it - c
    // it - d
    // it - e
    // it - f
    // it - g
    // it - h
    // it - i
    // it - j
    // it - k
}
5、数据类型转换
安全转换函数
fun main() {
    val number : Int = "123".toInt()
    // 字符串 转 Int
    println(number)
    // 输出 123

    // val number2 : Int? = "123.3".toInt()
    // double字符串 转 Int 是无法转换的会报错,所以为了防止报错
    val number2 : Int? = "123.3".toIntOrNull()
    // toIntOrNull 在转换失败时,返回 null
    println(number2)
    // 输出 null
    
    // double的函数如下,其他以此类推
    // "123.3".toDouble()
    // "123.3".toDoubleOrNull()
}
double 转 int
import kotlin.math.roundToInt

fun main() {
    println(33.5.toInt()) // 取整
    // 输出 33
    println(33.5.roundToInt()) // 四舍五入
    // 输出 34
    println(33.5513454.roundToInt()) // 四舍五入
    // 输出 34

    val r = "%.3f".format(44.5678) // 保留3位小数,四舍五入
    println(r)
    // 输出 44.568
}
6、Kotlin的内置函数
Kotlin 的 apply
import kotlin.math.roundToInt

fun main() {
    val info = "Hello World"
    println("info length : ${info.length}")
    println("info 最后的字符 : ${info[info.length-1]}")
    println("info 改全小写 : ${info.toLowerCase()}")

    println()

    // apply
    val infoNew : String = info.apply {
        // 该函数内 this 等于 info
        println("info2 length : ${length}")
        println("info2 最后的字符 : ${this[length-1]}")
        println("info2 改全小写 : ${toLowerCase()}")
        // apply 始终返回被调用的 info 本身
    }
    println(infoNew)
    // 输出 Hello World

    // 一般用于链式调用
    info.apply {
        println("操作一 : ")
    }.apply {
        println("操作二 : ")
    }.apply {
        println("操作三 : ")
    }
}
Kotlin的 let
fun main() {
    val list = listOf(1,2,3,4,5)
    val value1 = list.first() //第一个元素
    val result1 = value1 + 1 //取第一个元素进行操作
    println(result1)
    // 输出 2

    val result2 = listOf(1,2,3,4,5).let {
        // it 等于 list
        // let 会 return 最后一行的结果
        it.first() + it.first()
    }
    println(result2)
    // 输出 2
}
Kotlin的 run

与 let 和 apply 在使用上差不多

fun main() {
    val str = "Hello world"
    val r1 : Int = str.run{
        this.length
    }
    println(r1)
    // 输出 11

    str.run {
        // this == str本身
    }

    str.run(::isLong)
        .run {
            var str = "null"
            str = if (this){
                "Hi"
            }else{
                "Hao"
            }
            str // 最后一个值是返回值
        }
        .run {
            println(this)
            // 输出 Hi
        }

}

fun isLong(str: String) : Boolean{
    return str.length >= 10
}
Kotlin的 with
fun main() {
    val str = "Name"
	
	// with(参数,具名函数)
    with(str, ::println)
    // 输出 Name

    with(run {
             str + "HGW"
    }, ::println)
    // 输出 NameHGW

    with(str.apply {
         str + "Name2"
    },::println)
    // 输出 Name,因为apply只会返回自身

    with(str,::test)
    // 输出 test - Name
}

fun test(str:String){
    println("test - $str")
}
Kotlin的 also

跟 apply 差不多

fun main() {
    val r2 : Int = 123.also{
        it + 1
    }
    println(r2)
    // 输出 123
    // 与apply一样只会返回原始的值
    // 只不过它用的是 it 不是 this
}
Kotlin的 takeif
fun main() {
    val test = "hello"
    val str = test.takeIf {
        true
    }
    // true 返回自身
    println(str)
    // hello

    val str2 = test.takeIf {
        false
    }
    // false 返回null
    println(str2)
    // null
}
Kotlin的 takeUnless
fun main() {
    val test = "hello"
    val str = test.takeUnless {
        true
    }
    // true 返回null
    println(str)
    // null

    val str2 = test.takeUnless {
        false
    }
    // false 返回自身
    println(str2)
    // hello
}
7、Kotlin的集合
listOf 不可变集合
fun main() {
    val list = listOf("000", "001", "002", "003")

    println(list[3])
    // 输出 003

    println(list.getOrElse(2){"获取失败,数值越界了"})
    // 输出 002
    println(list.getOrElse(4){"获取失败,数值越界了"})
    // 输出 获取失败,数值越界了

    println(list.getOrNull(5)) // 没有5下标的元素
    // 输出 null
    println(list.getOrNull(1))
    // 输出 001
    println(list.getOrNull(10) ?: "越界")
    // 输出 越界
}
mutableListOf 可变集合
fun main() {
    val list : MutableList<String> = mutableListOf("000","001","002")
    list.add("003")
    println(list.toString())
    // 输出 [000, 001, 002, 003]
    list.add(0,"0000")
    println(list.toString())
    // 输出 [0000, 000, 001, 002, 003]
    list.remove("002")
    println(list.toString())
    // 输出 [0000, 000, 001, 003]
    list.removeAt(3)
    println(list.toString())
    // 输出 [0000, 000, 001]
}
mutator函数
import android.os.Build
import androidx.annotation.RequiresApi

@RequiresApi(Build.VERSION_CODES.N)
fun main() {
    val list : MutableList<String> = mutableListOf("000","001","002")
    list += "005"
    println(list.toString())
    // 输出 [000, 001, 002, 005]
    list -= "000"
    println(list.toString())
    // 输出 [001, 002, 005]

    list.removeIf {
        it.contains("2") // 返回true就删除当前it
    }
    println(list.toString())
    // 输出 [001, 005]

}
集合遍历
fun main() {
    val list = listOf(1,2,3,4,5,6,7)

    println(list)

    for (i in list){
        print("i - $i")
    }
    println()

    list.forEach {
        // it 就是 每一个元素
        print("forEach - $it")
    }
    println()

    list.forEachIndexed { index, i ->
        print("index : $index , i : $i")
    }
    println()
    
}
解构函数
import android.os.Build
import androidx.annotation.RequiresApi

fun main() {
    val list : List<String> = listOf("str01","str02","str03")
    val(v1,v2,v3) = list
    println("v1 : $v1 , v2 : $v2 , v3 : $v3")

    // "_" 是用来过滤元素的,表示不接收第一个
    val(_,n2,n3) = list
    println("n2 : $n2 , n3 : $n3")
}
set 集合
fun main() {
    val set : Set<String?> = setOf(null,"str","str","str","str04")
    println(set)
    // 输出 : [null, str, str04]
    // 不会有重复元素。

    // 获取元素
    println(set.elementAt(0))

    // 防止报错
    println(set.elementAtOrElse(3){"越界了"})

    // 防止获取 null
    // 获取到数据为 null ,或者报错异常的时候
    println(set.elementAtOrNull(0) ?: "越界1")
    println(set.elementAtOrNull(22) ?: "越界2")
}
集合转换
fun main() {
    val list : MutableList<String> = mutableListOf("001","001","002")
    println(list)
    val set  = list.toSet() // 通过转换成功set去重
    println(set)
    val list02 = list.distinct() // 去重
    // 源码:
    // public fun <T> Iterable<T>.distinct(): List<T> {
    //    return this.toMutableSet().toList()
    //}
    println(list02) 
}
数组
fun main() {
    val intArray = intArrayOf(1,2,3,4,5)
    println(intArray[0])
    println(intArray[1])
    println(intArray[2])
    println(intArray[3])
    println(intArray[4])

    println()

    // 越界返回 -1
    println(intArray.elementAtOrElse(5){-1})
    // 判空
    println(intArray.elementAtOrNull(200) ?: -1)

    // 集合 转 数组
    val charArray = listOf('1','2','3').toCharArray()
    println(charArray)

    // arrayOf 随意存放对象的数值
    val arr = arrayOf(Object(), Object(),"String")
    println(arr.elementAt(0))
    println(arr.elementAt(1))
    println(arr.elementAt(2))
}
Map

1、创建
在这里插入图片描述
2、遍历
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3、可变Map
在这里插入图片描述

8、Kotlin的类
成员变量/属性/初始化

在这里插入图片描述
field关键字,field === 对应属性
在这里插入图片描述
val修饰类型属性
在这里插入图片描述
计算属性
在这里插入图片描述

构造函数

主构造函数
在这里插入图片描述
次构造

class MyTest(name:String){ // 主构造函数

    // 次构造函数,必须重写主构造函数
    constructor(name:String, age:Int) : this(name){
        println("次构造")
    }
}

如果不传参数
在这里插入图片描述
init代码块
在这里插入图片描述
构造过程的执行顺序
在这里插入图片描述
在这里插入图片描述
lateinit关键字
在这里插入图片描述
lazy关键字
在这里插入图片描述
open关键字
在这里插入图片描述

面试题

Kotlin与Java的主要区别是什么?

空安全:Kotlin在类型系统中直接区分可空和非空类型
扩展函数:无需继承即可为类添加新功能
数据类:自动生成equals(), hashCode(), toString()等方法
更简洁的语法:如lambda表达式、字符串模板、属性等
协程:轻量级线程支持

协程(方便的线程并发框架)

优化了并发编程的代码复杂度

在这里插入图片描述
并行请求
在这里插入图片描述
消除嵌套代码
在这里插入图片描述

suspend关键词

在这里插入图片描述

非阻塞式挂起

非阻塞只是看起来而已,会切换切换线程去做耗时操作,然后回来继续执行后续的逻辑(约等于,回调CallBack)

空安全(特性)

kotlin里面全部的值都不允许为空的
lateinit

Object / companion Object / top-level

Object 类 : 里面全部都行都是静态的
companion Object:嵌套在类里面使用,里面的值全都是静态的
top-level:脱离与Class的静态变量

const

静态常量,但是支持基础类型
const val s = “s” // 常量内敛

Kotlin中reified修饰符有什么用?inline

(约等于Java泛型)
使泛型类型参数在运行时保留
必须与inline函数一起使用

inline fun <reified T> checkType(obj: Any) = obj is T

inline 内敛优化
online 局部取消内敛优化
crossline 局部加强内敛优化

函数式编程

Kotlin中的高阶函数是什么?举例说明
kotlin
fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y)
}

val sum = calculate(5, 3) { a, b -> a + b }

解释Kotlin中的let, apply, run, with和also函数的区别

  • let: 对非空对象执行lambda,返回lambda结果
  • apply: 在对象上执行lambda,返回对象本身
  • run: 结合了let和apply的功能
  • with: 类似run但不作为扩展函数
  • also: 类似apply,但接收原始对象作为参数

Kotlin中的委托属性(property delegation)如何工作?

kotlin
class Example {
var p: String by Delegate()
}

class Delegate {
operator fun getValue(…): String { … }
operator fun setValue(…, value: String) { … }
}

22. Kotlin 中的密封类是什么?

有点像枚举
Kotlin 中的密封类是可以在其中定义一组有限的子类的类。它允许您限制继承层次结构并定义一组封闭的可能子类。

当您想要表示受限制的类型层次结构时,密封类非常有用,其中所有可能的子类都是预先已知的,并且应该在when表达式中进行详尽的处理。

sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val message: String) : Result()
    object Loading : Result()
}

fun processResult(result: Result) {
    when (result) {
        is Result.Success -> {
            println("Success: ${result.data}")
        }
        is Result.Error -> {
            println("Error: ${result.message}")
        }
        Result.Loading -> {
            println("Loading...")
        }
    }
}

在示例中,“Result”类是一个密封类,具有三个子类:“Success”、“Error”和“Loading”。 “processResult”函数演示了使用when表达式对所有可能的子类进行详尽的处理。

密封类提供了一种安全的方法来处理受限层次结构并启用详尽的模式匹配,使代码更加健壮且不易出错。

22. Kotlin 的 by接口委托

跟基础抽象类类似

Kotlin的扩展函数

就是可以为一个对象,随意添加一个新的函数(静态方法)

fun String.addExclamation(): String {
    return "$this!"
}

val message = "Hello"
val modifiedMessage = message.addExclamation() // 扩展函数使用

println(modifiedMessage) // 输出:Hello!

密封类 + 密封接口

其实就是一个“枚举”

sealed interface Shape

class Circle : Shape()
class Rectangle : Shape()

fun draw(shape: Shape) {
    when (shape) {
        is Circle -> println("Drawing a circle")
        is Rectangle -> println("Drawing a rectangle")
    }
}

fun main() {
    val circle: Shape = Circle()
    val rectangle: Shape = Rectangle()

    draw(circle) // 输出: Drawing a circle
    draw(rectangle) // 输出: Drawing a rectangle
}

对象表达式

就是匿名内部类

interface OnClickListener {
    fun onClick()
}

fun setOnClickListener(listener: OnClickListener) {
    // Implementation
}

fun main() {
    setOnClickListener(object : OnClickListener {
        override fun onClick() {
            println("Button clicked")
        }
    })
}

Kotlin面试题其一
Kotlin面试题其二

Compose

84

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值