zoukankan      html  css  js  c++  java
  • Kotlin基本语法和使用技巧

    基本语法

    val value: String? = "HelloWorld"
    val name: String = getName() ?: return  //如果是null就return
    println("$arg1 + $arg2 = ${arg1 + arg2}")    //字符串模板
    val FINAL_HELLO_CHINA = "HelloChina"   //类型可以不写,自动推导
    val args1 = arrayOf(1,2,3)
    val range: IntRange = 0..1024 // [0, 1024]
    val range_exclusive: IntRange = 0 until 1024 // [0, 1024) = [0, 1023]
        
    class A {
        var b = 0
        lateinit var c: String   //var延迟初始化用lateinit,使用 lateinit 关键字,变量在定义时不需要初始化,所以在使用questionTextView变量时,不需要加上 ? 和 !! 操作符。在使用第一次变量之前,一定要保证为questionTextView赋值 , 不然会出现空指针异常。
        lateinit var d: X
        val e: X by lazy {
            //val延迟初始化用lazy代理
            println("init X")
            X()
        }
        
        //第一次调用 get() 会执行已传递给 lazy() 的 lambda 表达式并记录结果, 后续调用 get() 只是返回记录的结果。
         private val linearLayoutManager by lazy {
            LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
        }
        
        var cc: String? = null //初始化成null不好
    }
    abstract class Person(open val age: Int) {
        //只有open的成员和类才能被继承,接口和抽象类默认是open的
        abstract fun work()
    }
    
    //没有三目运算符,可以使用if 表达式
    val max = if (a > b) a else b
    
    //对于bean对象可以这样写
    data class Forecast(val date: Date, val temperature: Float, val details: String)
        
    //Kotlin 的构造函数可以写在类头中,跟在类名后面
    class Person( var name:String){
    
        private var description: String? = null
    
        //在主构造函数中不能有任何代码实现,如果有额外的代码需要在构造方法中执行,你需要放到init代码块中执行
        init {
            name = "Zhang Tao"
        }
    
        internal fun sayHello() {
            println("hello $name")
        }
    
        fun printName(){
            println(name)
        }
    
        //这里我们让次级构造函数调用了主构造函数,完成 name 的赋值。
        // 由于次级构造函数不能直接将参数转换为字段,所以需要手动声明一个 description 字段,并为 description 字段赋值。
        constructor(name: String, description: String) : this(name) {
            this.description = description
        }
    
    }
    
    class Latitude private constructor(val value: Double) {
            companion object {//伴随对象
                //加上这个注解Java可以直接像静态那样调用,否则得Latitude.companion.ofDouble(3.0)
                @JvmStatic
                fun ofDouble(double: Double): Latitude {
                    return Latitude(double)
                }
    
                fun ofLatitude(latitude: Latitude): Latitude {
                    return Latitude(latitude.value)
                }
    
                @JvmField
                val TAG: String = "Latitude"
            }
        }
    
        class Manager : Driver, Writer {
            override fun write() {
    
            }
    
            override fun drive() {
    
            }
        }
    
      
    
    //扩展方法,不用运算符operator的话,用"abc".times(16)这样来调用,jva可以类名.times("abc", 16)调用
        operator fun String.times(int: Int): String {
            val stringBuilder = StringBuilder()
            for (i in 0 until int) {
                stringBuilder.append(this)
            }
            return stringBuilder.toString()
        }
    
    //函数引用
        val pdfPrinter = PdfPrinter()
            args.forEach(pdfPrinter::println)
            
             class PdfPrinter {
            fun println(any: Any) {
                kotlin.io.println(any)  //重名了可以用包名调用
            }
        }
    
       //常见的高阶函数
            val list = listOf<Int>(1, 2, 3, 5, 10, 8, 2)
            val newList = ArrayList<Int>();
            list.forEach {
                val newElement = it * 2 + 3
                newList.add(newElement)
            }
            //和上面一样,上面麻烦,map可以对集合进行操作,返回一个修改过得集合
            //flatmap,对集合的集合进行操作,省去了俩次遍历的麻烦
            val newList2 = list.map { it * 2 + 3 }
            val newList3 = list.map { Int::toDouble }
            newList3.forEach(::println)
            newList3.map(::println)  //和上面输出一样,但是又重新add了一个集合,不好,纯粹用于迭代的话会影响性能,实现里面还有一个数组
            
            //提取开头指定数量或符合指定条件的子集  
            list.takeWhile { it <= 3 }.forEach(::println)  //小于的去掉
            list.forEach {
                if (it % 2 == 0) {
                    println(it)
                }
            }
            list.filter { it.isEvent() }.forEach(::println)//过滤
                
            val person = findPerson();
            //person是可null的,所以需要?
            println(person?.age)
            println(person?.name)
            //上面太麻烦,findPerson加了?,所以后面不需要了,减少的判空操作。let可以安全调用
            findPerson()?.let { person ->
                person.work()
                println(person.age)
            }
            //还可以更简洁,person也不用写
            findPerson()?.apply {
                work()
                println(age)
            }
    //使用apply做对象的初始化
    return TextView(context).apply {
        text = "test"
        setOnClickListener(onClickListener)
    }
    
        //use不用close了
            BufferedReader(FileReader("hello.txt")).use {
                var line: String?
                while (true) {
                    //it表示当前对象BufferedReader,所以可以用它的方法
                    line = it.readLine() ?: break
                    println(line)
                }
            }
    
    

    使用技巧

    take是从集合中取前几个元素
    takeLast是从集合中取后几个元素
    sortedBy 排序
    过滤list,符合过滤条件的就是过滤结果
    filterNot把符合条件的过滤掉,剩下的是结果。这个操作和 filter 相反
    slice,取集合中的某一部分

    val numbers = listOf("one", "two", "three", "four", "five", "six")    
    println(numbers.slice(1..3))
    println(numbers.slice(0..4 step 2))
    println(numbers.slice(setOf(3, 5, 0))) 
    
    [two, three, four]
    [one, three, five]
    [four, six, one]
    
    val numbers = listOf("one", "two", "three", "four", "five", "six")
    println(numbers.takeWhile { !it.startsWith('f') })
    println(numbers.takeLastWhile { it != "three" })
    println(numbers.dropWhile { it.length == 3 })
    println(numbers.dropLastWhile { it.contains('i') })
    
    
    [one, two, three]
    [four, five, six]
    [three, four, five, six]
    [one, two, three, four]
    
    • 扩展函数(类似于工具类)
       fun toast(message: String, length: Int = Toast.LENGTH_SHORT) {
            Toast.makeText(this, message, length).show()
        }
       
       toast("hello")
       
        //扩展函数,我们就可以在每一个Activity中直接使用toast()函数了。
        fun Context.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
            Toast.makeText(this, message, duration).show()
        }
    

    !! 强⾏行行调⽤用符
    ?. 安全调⽤用符

    • kotlin默认不能空,变量类型后面跟?号定义,表明这是一个可空类型
    • ?. 代表着如果该类型为空的话就返回null不做后续的操作,如果不为空的话才会去访问对应的方法或者属性
    • !!. 代表着如果该类型为空的话就抛出NullPointerException,如果不为空就去访问对应的方法或者属性, 所以只有在很少的特定场景才用这种符号,代表着程序不处理这种异常的case了,会像java代码一样抛出NullPointerException。 而且代码中一定不用出现下面这种代码,会让代码可读性很差而且如果有空指针异常,我们也不能马上发现是哪空了:
      /*
        * 不推荐这样的写法:链式的连续用!!.
        * */
        val user = User()
        user!!.name!!.subSequence(0,5)!!.length
    

    在 Kotlin 中创建单例不用像 Java 中那么复杂,只需要把 class 换成 object 就可以了。

    object Sample {    val name = "A name"}
    
    //饿汉式的单例,并且实现了线程安全
    object A {  
    val number: Int = 1   、
    fun method() {       
    println("A.method()")   
      }
    }  
    
    

    companion 可以理解为伴随、伴生,表示修饰的对象和外部类绑定。类似静态变量
    写在顶级的函数(不需要在class里写方法)或者变量有个好处:在 Android Studio 中写代码时,IDE 很容易根据你写的函数前几个字母自动联想出相应的函数。这样提高了写代码的效率,而且可以减少项目中的重复代码。
    如果想写工具类的功能,直接创建文件,写 top-level「顶层」函数。

    创建数组,增加很多有用的工具函数
    contains()first()find()

    val strs: Array<String> = arrayOf("a", "b", "c")
    

    循环通过标准函数 repeat()

    repeat(100) {
    // todo
    }
    

    map也可以这样创建

    val map = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 3)
    

    listOf() 创建不可变的 List,mutableListOf() 创建可变的 List

    Kotlin 中集合分为两种类型:只读的和可变的。这里的只读有两层意思:
    集合的 size 不可变
    集合中的元素值不可变
    可以转换

    map.toMutableMap()
    

    构造器

    class User constructor(var name: String) {                                   // 直接调用主构造器    
    constructor(name: String, id: Int) : this(name) {    }                //  通过上一个次构造器,间接调用主构造器  
    constructor(name: String, id: Int, age: Int) : this(name, id) {      }
    }
    

    forEach:遍历每一个元素
    filter:对每个元素进行过滤操作,如果 lambda 表达式中的条件成立则留下该元素,否则剔除,最终生成新的集合
    map:遍历每个元素并执行给定表达式,最终形成新的集合
    flatMap:遍历每个元素,并为每个元素创建新的集合,最后合并到一个集合中

    Elvis 操作符
    通过 ?: 的操作来简化 if null 的操作

    fun validate(user: User) {   
    val id = user.id ?: return 
    // 验证 user.id 是否为空,为空时 return 
    }
    // 等同于
    fun validate(user: User) {    
    if (user.id == null) {        
    return   
    }    
    val id = user.id
    }
    

    == :可以对基本数据类型以及 String 等类型进行内容比较,相当于 Java 中的 equals
    === :对引用的内存地址进行比较,相当于 Java 中的 ==

    如果每个类型都去实现诸如 TextViewList、ActivityList 这样的具体的类型,显然是不可能的。因此就诞生了「泛型」,它的意思是把具体的类型泛化,编码的时候用符号来指代类型,在使用的时候,再确定它的类型

    使用关键字 out 来支持协变,等同于 Java 中的上界通配符 ? extends。
    使用关键字 in 来支持逆变,等同于 Java 中的下界通配符 ? super。

    var textViews: List<out TextView>
    var textViews: List<in TextView>
    

    Kotlin 标准函数
    使⽤用时可以通过简单的规则作出一些判断

    • 返回⾃自身
      从 apply 和 also 中选
      作⽤域中使⽤ this 作为参数选择 apply
      作⽤域中使⽤ it 作为参数选择 also
    • 不需要返回⾃自身
      从 run 和 let 中选择
      作用域中使用 this 作为参数,选择 run
      作用域中使用 it 作为参数,选择 let

    apply 适合对一个对象做附加操作的时候
    let 适合配合空判断的时候
    with 适合对同一个对象进行多次操作的时候

    协程就是kotlin官方提供的线程api

    属性委托
    有些常见的属性操作,我们可以通过委托方式,让它实现,例如:lazy 延迟属性: 值只在第一次访问的时候计算
    类委托
    可以通过类委托来减少 extend类委托的时,编译器回优使用自身重新函数,而不是委托对象的函数

    interface Base{
    fun print()
    }
    
    case BaseImpl(var x: Int):Base{
    
    override fun print(){
    print(x)
    }
    
    }
    // Derived 的 print 实现会通过构造函数的b对象来完成class Derived(b: base): Base by b
    

    委托就是代理

      //接口代理,可以不是必须实现接口或抽象类的方法
        class SeniorManager(val driver: Driver, val writer: Writer) : Driver by driver, Writer by writer
    
        class CarDriver : Driver {
            override fun drive() {
                println("开车呢")
            }
        }
    
        class PPTWriter : Writer {
            override fun write() {
                println("做PPT呢")
            }
    
        }
    
        interface Driver {
            fun drive()
        }
    
        interface Writer {
            fun write()
        }
        
    
            val driver = CarDriver()
            val writer = PPTWriter()
            val seniorManager = SeniorManager(driver, writer)
            seniorManager.drive()
            seniorManager.write()
                
      //类委托
        interface Base {
            fun print()
        }
        class BaseImpl(val x: Int) : Base {
            override fun print() { print(x) }
        }
        class Derived(b: Base) : Base by b//实现继承的代替方式
        fun main(args: Array<String>) {
            val b = BaseImpl(10)
            Derived(b).print() // prints 10
        }
    

    使用 类名::class 获取的是 Kotlin 的类型是 KClass
    使用 类名::class.java 获取的是 Java 的类型
    Any
    Kotlin 的顶层父类是 Any ,对应 Java 当中的 Object ,但是比 Object 少了 wait()/notify()等函数
    Unit
    Kotlin 中的 Unit 对应 Java 中的 void
    在 Java 中通过 「类名.this」 获取目标类引用
    在 Kotlin 中通过「this@类名」获取目标类引用

  • 相关阅读:
    杂项收集,包括-发邮件、二维码生成、文件下载、压缩、导出excel
    SQL2008删除大量数据
    优秀程序设计的18大原则
    多线程基础
    SQL金典
    [读书笔记]高效程序员的45个习惯:敏捷开发修炼之道
    Unity 查找资源引用工具
    Unity自动生成各种机型分辨率效果工具
    Unity Editor模式 Invoke()函数 失效
    Unity 特效 粒子 自动播放
  • 原文地址:https://www.cnblogs.com/sixrain/p/11631063.html
Copyright © 2011-2022 走看看