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,取集合中的某一部分java

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()
    }

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

  • 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()app

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

循环经过标准函数 repeat()ide

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()

构造器ui

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@类名」获取目标类引用

相关文章
相关标签/搜索