Kotlin语言有几个优势
1. 简洁 它大大减少你需要写的样板代码的数量。
2. 安全 避免空指针异常等整个类的错误。
3. 通用 构建服务器端程序、Android 应用程序或者在浏览器中运行的前端程序。
4. 互操作性 通过 100% Java 互操作性,利用 JVM 既有框架和库。
5. 资源 对内存更好的管理。
https://blog.csdn.net/u013064109/article/details/80088158
1、大量减少判空,null指针错误;
2、免去findViewById操作;
3、简洁的代码更少的bug量;
4、变量类型+?表示变量值可为null, ?. 是对象不为 null 时执行代码,?: 是对象 为 null 执行代码;
5、var:可变变量,val:不可变变量;
6、对象声明:使用 object 关键字来声明一个对象;(object关键字用法之一)
7、对象表达式:是一种代替Java中的匿名内部类的方法;
a、匿名内部类在Kotlin中使用object关键字来进行编写;
b、可以实现多个接口;
c、Java中,被匿名内部类访问的变量必须被final修饰符修饰,Kotlin中没有这种限制,对象表达式可以直接访问创建它的函数内部的变量,并且修改其值;
8、kotlin内置大量函数简化代码;
9、kotlin不支持java的三目运算符,使用if表达式代替三目运算符:if(条件) xxx else xxx;
10、简洁的set/get;
11、kotlin中对象调用属性=调用set/get;
12、7种中缀表达式计算规则
and如果对应位都是1,则结果为1,否则为0
or如果对应位都是0,则结果为0,否则为1
xor如果对应位值相同,则结果为0,否则为1
inv按位翻转操作数的每一位,即0变成1,1变成0
shl按位左移指定的位数,相当于乘以2的N次方。移掉的省略,右边缺失的位,用0补齐
shr按位右移指定的位数,相当于除以2的N次方,移掉的省略,左边缺失的位,如果是正数则补0,若为负数,可能补0或补1,这取决于所用的计算机系统
ushr按位右移指定的位数,移掉的省略,左边缺失的位,用0补齐
13、lambda基本语法
lambda的标准形式基本声明满足三个条件:
含有实际参数
含有函数体(尽管函数体为空,也得声明出来)
以上内部必须被包含在花括号内部
14、方法说明:TODO("not implemented") 有点类似于java的//todo,但是不同的是,因为它的方法告诉我们,它会抛出一个异常,也就是上面这个方法会导致程序崩溃。它的好处是:配合IDE自动声明的TODO, 会强制开发者去实现这个TODO或者删除它。
15、kotlin里面的构造函数是用constructor关键字表示。kotlin里面的构造函数分为主构造函数和次构造函数。主构造函数只能有一个,次构造函数个数不限制,可以有一个或者多个。
a、主构造方法如下,跟在类名后面
class Person constructor(name:String){}
当主构造方法没有任何注解或者可见性修饰符时,可以省略;
主构造方法是没有方法体的,那么我们需要初始化的数据应该放到init方法。
b、次构造方法,一个无参的次构造方法,一个有一个参数的次构造方法
class Person {
constructor(){}
constructor(name:String){}
}
结论:不管是什么构造方法,先执行init模块逻辑,后执行构造方法的逻辑
16、重写set/get方法
比如:
var name:String=""
set(value){
field=value+"www"
}
get(){
return field+"zzz"
}
重点:
你想重写哪个属性的set,get方法,就在哪个属性下方写set,get方法,不用成对出现,可以只重写set方法,也可以只重写get方法;
用field表示你想要的值;
17、lateinit 和 by lazy
a、lateinit(延迟初始化属性)
一般地,属性声明为非空类型必须在构造函数中初始化(我们知道,kotlin中默认是空安全的,任何属性的声明都必须有初始化值,如果支持可空”?”,才能把属性声明为null)。然而这样经常不方便,例如:属性可以通过依赖注入来初始化,或者单元测试的setup方法中初始化,这种情况下,你不能在构造函数内提供一个非空初始器,但你仍然想在类体中引用该属性时避免空检查。为处理这种情况,我们可以使用lateinit。
该修饰只能用于类体中(不是在主构造函数中)声明的var属性,注意是var(可变属性)并且仅当该属性没有自定义getter或setter时,该属性必须是非空类型,并且不能是原生类型。
在初始化前访问一个lateinit属性会抛出一个特定异常,该异常明确标识该属性被访问及它没有初始化的事实。
b、by lazy(惰性初始化)
惰性初始化是一种常见的模式,直到第一次访问该属性的时候,才根据需要创建对象的一部分,当初始化过程消耗大量资源并且在使用对象时并不总是需要数据时,这个非常有用。
首先需要注意的是:
by lazy只能作用于val关键字标注的属性。
当属性用到的时候才会初始化”lazy{}”里面的内容
而且再次调用属性的时候,只会得到结果,而不会再次执行lazy{}的运行过程
总结:以上可以看出两个都是用来初始化属性的,但是有点互补的意思。可以根据不同情况选择使用。
18、在Kotlin中 !!. 跟 ?. 都是用于判断空参数异常的
?. 意思是如果这个参数为空, 就跳过这一行, 程序继续执行下去
!!. 的意思是这个参数如果为空, 就抛出异常
19、Kotlin不安全和安全类型转换操作符
a、不安全的转换操作符:as
有时无法转换变量并抛出异常,这称为不安全转换。 不安全的强制转换由中缀运算符执行。
可以为空的字符串(String?)不能转换为非null字符串(String),这会引发异常。
b、Kotlin安全转换操作符:as?
Kotlin提供安全转换操作符:as?安全地转换成一种类型。 如果无法进行转换,则返回null,而不是抛出ClassCastException异常。
让我们看一个例子,尝试转换任何类型的字符串值,程序员最初不知道编译器为可null string类型和可null的int类型。 如果可能的话,它会抛出值,或者返回null而不是抛出异常,甚至无法进行强制转换。
20、Kotlin系列之with、takeIf 、takeUnless、run、repeat、let、apply、also函数的使用
a、with
定义:fun
功能:将对象作为函数的参数,在函数内可以通过 this指代该对象。返回值为函数的最后一行或return表达式。
场景:调用同个对象多个方法;对象值映射/方法调用;等等
实例:
b.、takeIf 和 takeUnless
takeif
定义:fun
功能:传递一个函数参数,如果函数结果为true,返回T对象,否则返回null。
实例:使用File文件时通常会判断file是否存在
takeUnless
定义:fun
功能:与takeIf相反,参数函数返回false时返回T对象,否则返回null,这里不再举例。
c、run
定义:
(1)fun run(block: () -> R): R
(2)fun T.run(block: T.() -> R): R
功能:调用run函数返回值为函数体最后一行,或return表达式。
场景:适用于let,with函数任何场景;
实例:
返回return表达式,return后面的代码不再执行(注意写法@run)
d、repeat
定义:fun repeat(times: Int, action: (Int) -> Unit)
功能:重复执行action函数times次,times从0开始
场景:顾名思义,重复执行;
实例:与for循环功能类似,例如
e、let
定义:fun
功能:调用对象(T)的let函数,则该对象为函数的参数。在函数内可以通过 it 指代该对象。返回值为函数的最后一行或指定return表达式。
场景:更加适用于处理不为null的操作场景;
实例:有点类似于run(),let在使用中可用于空安全验证,变量?.let{}
f、apply
定义:fun
功能:调用对象的apply函数,在函数范围内,可以任意调用该对象的任意方法,并返回该对象。
场景:多个扩展函数链式调用;数据多层级处理;
实例:
g、also
定义:fun
功能:调用对象的also函数,在函数块内可以通过 it
指代该对象,返回值为该对象本身。(注意其和let函数的区别,let返回的是最后一行,also返回的是对象本身)
场景:适用于let函数的任何场景,一般可用于多个扩展函数链式调用;
实例:需要返回对象本身(this)的情况下,例如建造者模式。
21、扩展函数
不通过继承或使用 Decorator 模式在已有类中添加新的方法来实现某一具体功能。
Kotlin的扩展函数可以让你作为一个类成员进行调用的函数,但是是定义在这个类的外部。这样可以很方便的扩展一个已经存在的类,为它添加额外的方法。在Kotlin源码中,有大量的扩展函数来扩展java,这样使得Kotlin比java更方便使用,效率更高。通常在java中,我们是以各种XXXUtils的方式来对已经存在的类进行功能的扩展。但是有了扩展函数,我们就能丢弃让人讨厌的XXXUtils方法工具类。
大多数情况下,我们直接在包里定义扩展函数。这样我们就可以在整个包里面使用这些扩展,如果我们要使用其他包的扩展,我们就需要导入它。导入扩展函数跟导入类是一样的方式。
fun Button.enable(et: EditText, method: () -> Boolean){
val btn = this
et.addTextChangedListener(object : TextWatcher{
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
btn.isEnabled = method()
}
})
}
以上代码
Button扩展了一个方法enable
第一个参数EditText因为需要监听它的变化
第二个参数是方法方法的作用就是判断是否所有输入框都不为空返回值是Boolean
在EditText监听中动态设置按钮是否可用
使用扩展方法
mRegisterBtn.enable(mMobileEt,{isBtnEnable()})
22、with函数最后一个参数是一个函数,可以把函数提到圆括号的外部。
23、also函数的结构实际上和let很像唯一的区别就是返回值的不一样,let是以闭包的形式返回,返回函数体内最后一行的值,如果最后一行为空就返回一个Unit类型的默认值。而also函数返回的则是传入对象的本身。
24、Kotlin 标签@使用
标签:显示标签和隐式的标签
在Kt中任何表达式都可以用标签label来标记。标签的格式为标识符后跟@符号,例如: adc@、jarOfLove@都是有效的标签。
我们可以用Label标签来控制return、break或continue的跳转行为。
Kt的函数是可以被嵌套的。它有函数字面量、局部函数等。有了标签限制return,我们就可以从外层行数返回了。
在比较复杂的方法里面用标签比较方便。
25、?: Elvis 操作符
Elvis运算符 ?: 又称 null 合并运算符。
功能:
接受两个运算数,
若第一个运算数不为null,运算结果就是第一个运算数;
若第一个运算数为null,运算结果就是第二个运算数。
改良 Elvis
Elvis 操作符很方便,但只能连接表达式,我们可以写一个扩展函数来作为加强版的 Elvis 操作符。
inline infix fun
if (this == null) {
return block(this)
}
return this
}
使用方式:
val file= java.io.File("C:\\FakeFile")
val parent=file?.toString() ifNull {
// do something here
}
26、Kotlin——初级篇(八):关于字符串(String)常用操作汇总
https://juejin.im/post/5b0ae06df265da0db64e3d63
27、in / out
Kotlin 泛型
JAVA 里 List
Kotlin 中的 out A 类似于 Java 中的 xx extends A,即泛型参数类型必须是 A或者 A 的子类,用来确定类型的上限
Kotlin 中的 in A 类似于 Java 中的 xx super A,即泛型参数类型必须是 B 或者 B 的父类,用来确定类型的下限
根据以上的内容,我们还可以这样来理解什么时候用 in 和 out:
父类泛型对象可以赋值给子类泛型对象,用 in;
子类泛型对象可以赋值给父类泛型对象,用 out。
28、 kotlin为数组增加了一个Array类,为元素是基本类型的数组增加了xxArray类(其中xx也就是Byte,Short, Int等基本类型)
Kotlin创建数组大致有如下两种方式:
1.使用arrayOf(), arrayOfNulls(),emptyArray()工具函数。
2.使用Array(size: Int, init:(Int) -> T)
fun getLayoutId1(): (Int) -> Int
29、Kotlin集合
kotlin集合类同样有两个接口派生:Collection和Map。但Kotlin的结合被分成两个大类,可变集合和不可变集合。只有可变集合才可以添加修改,删除等处理操作。不可变集合只能读取元素。
上图为kotlin提供的集合,通过上图可以看出kotlin的集合实现类比java更少,他只是提供了HashSet, LinkedHashSet, ArrayList这三个常见的实现类,如果开发者需要使用TreeSet, LinkedList集合实现类依然可以使用java集合框架提供的类。
set集合,Kotlin提供了如下函数来创建Set集合
setOf();该函数返回不可变的Set集合,该集合可以接收0个或多个参数,这些参数将作为集合的元素。
mutableSet0f():该函数返回可变的MutableSet集合,
hashSetOf():该函数返回可变的HashSet集合,
linkedSetOf():该函数返回可变的LinkedHashSet集合。
sortedSetOf():该函数返回可变的TreeSet集合, 用法同下。
在kotlin1.1的时候setof返回的类型就是linkedHashset。 setof, linkedSetOf是有序的, hashSetOf和sortedSetOf是无序的。 所以好多朋友都是set是无序的,我感觉这样说很片面。
set集合的工具方法里有
all, any, associateBy 和数组的一样,用法也一样就不解释了。
set.drop(2) 返回删除set集合前面两个元素后的集合。
set.filter({"java" in it}) 对set集合进行过滤,返回包含java的集合。
set.find({"java" in it}) 如果集合里元素有可以包含java的返回true,否者返回false
set.add; set.remove; set.clear ...跟java一样。(set集合不允许重复,java也是一样)
还有去两个集合的交集,并集等等。方法还有很多。如有兴趣请查看kotlin官网。
list集合,Kotlin提供了如下函数来创建list集合
listOf(); 返回不可变的集合
listOfNull(); 返回不可变集合,和前一个函数的唯一的区别是,该函数会自动去掉传入的null,也就是说返回的时候不会返回null,会过滤掉。
mutableListOf(); 该函数返回可变的MutableListOf()集合
第一个listOf实际上返回的是ArrayList
使用list的方法:
list.indexOf("java")取得坐标的位置。
list.subList 返回List的子集合。list.subList(1, 3) 包含1不包含3
工具类和set很相似,具体的可以自己尝试一下。
Map集合
mapOf(); 该函数返回不可变的Map集合。
mutableMapOf(); 该函数返回可变的MutableMap集合。
其实mapOf() 返回的是LinkedHashMap()。
hashMapOf(); 返回可变的HashMap()集合。
linkedMapOf(); 返回可变的LinkedHashMap集合。
Kotlin为Map集合同样扩展大量方法,这些方法与Kotlin为Set集合提供的方法也大致相似。区别就是对key-value进行了调整。
map.all({it.key.length > 5 && it.value.length > 5})
map.filter({"java" in it.value}) 。。。。。。
对于map的添加删除和java一样 put, remove。我就不举例子了。
遍历map
for(en in map.entries) {}
for(key in map.keys) {}
for(value in map.value) {}
map还可以用map[key] = value,来代替map.put("key", value)
到这里kotlin的数组和集合基本的用法基本上讲完了,其实和java的数组和集合基本相似,就是多了一些可变集合和不可变集合,以及提供的方法更多了一些,方便我们开发。其实kotlin自己并没有实现任何集合与数组都是调用java的。所以对于最求性能的开发者来说完全可以按照java的结合的每个的优点缺点来调用就好。
30、委托属性
有一些常见的属性类型,虽然我们可以在每次需要的时候手动实现它们, 但是如果能够为大 家把他们只实现一次并放入一个库会更好(当然也可以自定义委托啦)。
例如包括
延迟属性(lazy properties): 其值只在首次访问时计算,
可观察属性(observable properties): 监听器会收到有关此属性变更的通知,
把多个属性储存在一个映射(map)中,而不是每个存在单独的字段中。
语法是: val/var <属性名>: <类型> by <表达式> 。在 by 后面的表达式是该 委托, 因为属性 对应的 get() (和 set() )
会被委托给它的 getValue() 和 setValue() 方法。 属性的委托不必实现任何的接口,但是需要提供一个 getValue() 函数(和 setValue() ——对于
var 属性)。
31、If not null 缩写println(files?.size)
If not null and else 缩写println(files?.size ?: "empty")
if null 执行一个语句 val email = data["email"] ?: throw IllegalStateException("Email is missing!")
if not null 执行代码 data?.let {
…… // 代码会执行到此处, 假如data不为null
}
32、
扩展函数 不需要传入被扩展的类型参数 可以直接被其子类调用
例:Toast工具
新建一个Util.kt
fun Context.ShowToast(String toastMsg) : Toast {
var toast=Toast.makeText(this,toastMsg,Toast.LENGTH_SHORT)
toast.show()
return toast
}
在Activity中 直接调用 showToast(msg)
在fragment中可以getActivity.showToast(msg)
扩展函数并不是真正地修改了原来的类,它是以静态导入的方式来实现的。扩展函数可以被声明在任何文件中,因此有个通用的实践是把一系列有关的函数放在一个新建的文件里。
33、三元表达式
if(xxx){xxx} else {xxx}
34、inline 和 noinline
https://blog.csdn.net/Jaden_hool/article/details/78437947
inline关键字实际上增加了代码量,但是提升了性能,而且增加的代码量是在编译期执行的,对程序可读性不会造成影响。
body参数需要传递给其他非inline方法,不是一个函数对象了,也就不能作为一个参数传递了,除非在body参数前加上noinline关键字。
35、在Java中调用Kotlin类的参数默认值对应的重载问题
Kotlin给我们提供了一个注解:@JvmOverloads,使用这个注解后Kotlin就会向 Java 调用者暴露多个重载。
如我们在Kotlin中写如下函数:
fun f(a: String, b: Int = 0, c: String = "abc") { }
相当于在Java中如下声明:
void f(String a, int b, String c) { }
默认参数不会起到任何作用。
如果使用@JvmOverloads注解:
@JvmOverloads fun f(a: String, b: Int = 0, c: String = "abc") { }
相当于在Java中如下声明:
void f(String a, int b, String c) { }
void f(String a, int b) { }
void f(String a) { }
这样就能按照自己的连接Java和Kotlin了。
该注解也适用于构造函数、静态方法。如:
data class Person @JvmOverloads constructor(var name: String, var age: Int,var height: Float = 1.8f)
36、Kotlin for循环的几种使用方法
1、在Kotlin中想正序遍历1-100的数值可以这样写:
for (index in 1..100){
print(index)
}
2、想倒序遍历就该使用标准库中定义的downTo()函数:
for (index in 100 downTo 1){
print(index)
}
3、想不使用1作为遍历的步长,可以使用step()函数:
for(index in 1..100 step 2){
print(index)//会输出1..3..5......
}
4、要创建一个不包含末尾元素的区间:
for(index in 1 until 10){
println(index)//输出0..9
}
5、遍历一个数组/列表,想同时取出下标和元素:
valarray=arrayOf("a","b","c")
for( (index,e) in array.withIndex()) {
println("下标=$index----元素=$e")
}
6、遍历一个数组/列表,只取出下标:
valarray=arrayOf("a","b","c")
for( index in array.indices) {
println("index=$index")//输出0,1,2)
}
7、遍历取元素:
valarray=arrayOf("a","b","c")
for( element in array) {
println("element=$element")//输出a,b,c)
}
37、Kotlin的那些List相关的操作符
https://blog.csdn.net/LitterLy/article/details/106543535
38、操作符与操作符重载一
https://www.cnblogs.com/Jetictors/p/8241212.html
https://www.yiibai.com/kotlin/operator-overloading.html
39、如何在Kotlin中将List转换为Map?(How to convert List to Map in Kotlin?)
You have two choices:
The first and most performant is to use associateBy function that takes two lambdas for generating the key and value, and inlines the creation of the map:
val map = friends.associateBy({it.facebookId}, {it.points})
The second, less performant, is to use the standard map function to create a list of Pair which can be used by toMap to generate the final map:
val map = friends.map { it.facebookId to it.points }.toMap()
40、Kotlin 函数魔法 - 双冒号
:: 的作用
支持函数作为参数,是 Kotlin 自带的特性,:: 的作用跟这个特性无关,不过它能够使函数调用更为简
一般情况下,this::xxx 可以简化为 ::xxx。
:: 只能将函数作为参数来使用,不能直接用来调用函数: