kotlin更安全
这是它最重要的优势,空引用由类型系统控制,你不会再遇到NullPointerException。这个空指针异常就像一个隐藏的定时炸弹,指不定啥时候就炸了。
在Kotlin中调用Java代码,Java代码中需要使用上非空注解。
代码简洁
使用Lambda 表达式,大量节省末班代码,特别是重复多余的findViewById。都说越少的代码越能减少错误。
函数式支持
使用高阶函数,可以将其作为返回值或参数值使用,特别方便。
什么是高阶函数呢?就是以函数作为参数,又以函数作为返回值就是高阶函数,而每个函数又对应着Lambda表达式。
常见的高阶函数map()、forEach()、flatMap()、reduce()、fold()、filter()、takeWhile()、let()、apply()
扩展函数
Kotlin同C#类似,能够扩展一个类的新功能而无需继承该类或使用像装饰者这样的任何类型的设计模式。Kotlin支持扩展函数和扩展属性。
1) 表达式可以直接作为函数返回值
2)扩展函数: fun 类名.扩展方法名(参数列表){方法体} 或者 fun 类名.扩展方法名(参数列表) = 表达式
fun MyClass.add(a:Int,b:Int) = a+b
3)扩展属性:var 类名.扩展属性 / 对应其他方法
var MyClass.d: String
get() = "sdasda"
set(value){d = value}//MyClass的扩展成员变量d
Kotlin中没有静态成员
对应的解决方案是伴生类
与java可互相调用
Kotlin的标准库更多的是对Java库的扩展,但是在Kotlin中可以使用Android库。在Kotlin和Java代码中可以互相调用,完美无障碍。
import A.Student as AS//将A包下的Student类取外号为"AS"
import B.Studnet as BS//将B包下的Student类取外号为"BS"
var intRange:IntRange = 0..1024//区间为[0,1024],注意是全闭的
var intRange2:IntRange = 0 until 1024//区间为[0,1024),注意是半闭半开的,包头不包尾
println("50是否存在与区间[0,1024]:"+intRange.contains(50))
println("-3是否存在与区间[0,1024):"+intRange.contains(-3))
//遍历区间
for(i in intRange){
println(i)
}
Kotlin中一般声明数组开始用intArrayOf和arrayOf来声明
Kotlin的权限修饰符没有了default,对应的改成了internal
在Kotlin中使用"“等价Java 中的equals()方法。使用”=“来等价Java中的”==",比较两个引用是否是同一个对象。
Kotlin中没有了Switch语句,用when来替代,它更加强大,它的判断值可以是表达式。
Kotlin中构造器需要使用constructor这个关键字,或者有个特殊默认的构造方式,这种叫做主构造函数
class Student(var name:String,var age:Int)//构造器的特殊写法
Kotlin中从属于类的函数叫做"成员方法",不从属于类的叫做函数,如一下参数是以方法块的形式表现,这个就是"函数"
Kotlin的默认访问权限是public,而非Java中默认的访问权限default。
final:是Kotlin的默认修饰符。如果你想你的类能被继承你需要使用open来修饰。
data:这个修饰符很好用,也很有特色。用data修饰后:
1)会自动将所有成员用operator声明,自动为成员生成getter和setter。
2)自动重写了equals()/hashCode()和toString()方法
3)data类没有无参构造函数,这感觉是个坑,所以Kotlin官方给出了解决方案,就是使用NoArg(无参构造函数)和AllOpen(可被继承)来解决问题。
在Kotlin的接口中可以实现方法不报错,如下在Java中会报错,但是在Kotlin中不会报错。
interface JieKou{
fun A(){
//方法体a
println("接口里面的方法,我是方法体")
}
}
var ab = A.AB() //实例化A类中的静态内部类AB
var ac = A().AC() //实例化A类中的非静态内部类AC
A a=new A();
A.AC ac =a.new AC();
A.AC ac=new A.AC();
//文件名 Test.kt
class Student(var name:String,var age:Int){
}
fun getMessage(){//这个扩展方法被编译Test.kt中的静态方法public static getMessage(Student student)
println("")
}
var results = Regex(geShi).split(str)//Regex为Kotlin中处理正则表达式的工具类
这个特性我需要单独来讲解说明,在Kotlin中没有static,我们在伴生类中的变量和方法相当于静态变量和静态方法。
companion object {//静态方法和变量都应该写在这里面
var a:Int = 3;//静态变量
fun get():Int{
return a
}
}
1.@JavaFiled:将属性编译为Java变量
2.@JvmStatic:将对象的方法编译成Java静态方法,通常应用与伴生对象
3.@JvmOverloads:默认参数生成重载方法
4.@file:JvmName:指定Kotlin文件编译后的类名
let
let扩展函数的实际上是一个作用域函数,当你需要去定义一个变量在一个特定的作用域范围内,let函数的是一个不错的选择;let函数另一个作用就是可以避免写一些判断null的操作。
//1)判断object为null的操作
object?.let{//表示object不为null的条件下,才会去执行let函数体
it.todo() //在函数体内使用it替代object对象去访问其公有的属性和方法
1000
}
在函数块内可以通过 it 指代该对象。返回值为函数块的最后一行或指定return表达式。
它的使用场景如下:
场景一: 最常用的场景就是使用let函数处理需要针对一个可null的对象统一做判空处理。
场景二: 然后就是需要去明确一个变量所处特定的作用域范围内可以使用
with
with函数和前面的几个函数使用方式略有不同,因为它不是以扩展的形式存在的。它是将某对象作为函数的参数,在函数块内可以通过 this 指代该对象。返回值为函数块的最后一行或指定return表达式。
如下两代码是等价的:
val result = with(user, {
println("my name is $name, I am $age years old, my phone number is $phoneNum")
1000
})
val result = with(user) {
println("my name is $name, I am $age years old, my phone number is $phoneNum")
1000
}
使用场景
适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类的方法即可,经常用于Android中RecyclerView中onBinderViewHolder中,数据model的属性映射到UI上。
override fun onBindViewHolder(holder: ViewHolder, position: Int){
val item = getItem(position)?: return
with(item){
holder.tvNewsTitle.text = StringUtils.trimToEmpty(titleEn)
holder.tvNewsSummary.text = StringUtils.trimToEmpty(summary)
holder.tvExtraInf.text = "难度:$gradeInfo | 单词数:$length | 读后感: $numReviews"
...
}
}
run
run函数实际上可以说是let和with两个函数的结合体,run函数只接收一个lambda函数为参数,以闭包形式返回,返回值为最后一行的值或者指定的return的表达式。
override fun onBindViewHolder(holder: ViewHolder, position: Int){
getItem(position)?.run{
holder.tvNewsTitle.text = StringUtils.trimToEmpty(titleEn)
holder.tvNewsSummary.text = StringUtils.trimToEmpty(summary)
holder.tvExtraInf = "难度:$gradeInfo | 单词数:$length | 读后感: $numReviews"
...
}
}
适用于let,with函数任何场景。因为run函数是let,with两个函数结合体,准确来说它弥补了let函数在函数体内必须使用it参数替代对象,在run函数中可以像with函数一样可以省略,直接访问实例的公有属性和方法,另一方面它弥补了with函数传入对象判空问题,在run函数中可以像let函数一样做判空处理
apply
从结构上来看apply函数和run函数很像,唯一不同点就是它们各自返回的值不一样,run函数是以闭包形式返回最后一行代码的值,而apply函数的返回的是传入对象的本身。
以下与with函数不一样,其结果值result指代的是user
fun main() {
val user = User("Kotlin", 1, "1111111")
val result = user.apply {
println("my name is $name, I am $age years old, my phone number is $phoneNum")
1000
}
println("result: $result")
}
使用场景
1)apply一般用于一个对象实例初始化的时候,需要对对象中的属性进行赋值。或者动态inflate出一个XML的View的时候需要给View绑定数据也会用到,这种情景非常常见。
mSheetDialogView = View.inflate(activity, R.layout.biz_exam_plan_layout_sheet_inner, null).apply{
course_comment_tv_label.paint.isFakeBoldText = true
course_comment_tv_score.paint.isFakeBoldText = true
course_comment_tv_cancel.paint.isFakeBoldText = true
course_comment_tv_confirm.paint.isFakeBoldText = true
course_comment_seek_bar.max = 10
course_comment_seek_bar.progress = 0
}
2) 也和let函数一样用于去进行判null。