当前如果全面使用kotlin来代替java,能够给我们带来什么便利呢
好处很多啊
1) 更多的编程方式,支持OO、过程式和FP
2) 空安全,更优雅的解决了NPE
3) 与Java无缝集成,支持双向的调用
4) 支持操作符重载
5) 采用Any作为基类解决了装箱和拆箱的问题,可以统一为Int/Long
6)没有Checked Exception
7) 支持侵入式编程
8) 支持参数默认值
1.1 java 自动转换成kotlin
kotlin项目开发总结有介绍如何使用,这个是有JetBrains提供的,目前已经集成到了IDEA/AS, 虽然它不是很完美(我的上篇博客也已经介绍到了),但是对比重新用Kotlin开发一个完全一样功能的类来说,可以节省不少时间。
1.2 lateinit Delegates.notNull and lazy
kotlin的null安全监测是个非常好的特性,但是也有有个问题,比如:
var aMap: AMap? = null
onCreate(){
aMap = ...
aMap!!.projection
....
}
1
2
3
4
5
6
7
虽然我们可以保证aMap已经在onCreate方法定义了,但是因为我们在定义aMap的时候是AMap?类型,所以在以后使用的都必须使用aMap!!来告诉编译器aMap不为null,会显得非常麻烦。幸运的是kotlin已经帮我们考虑到了应对方法
lateinit var name: String
var age: Int by Delegates.notNull()
1
2
通过上面两种方法,可以在定义的时候不提供初始化,可以延迟到需要的时候,但是就像我在kotlin项目开发总结说的,需要慎用,除非你能确保不会在后面遗漏掉重新赋值,否则会在运行时报空指针错误,这就浪费了kotlin的null安全监测这个非常好的特性。
lazy代理是个很好用的东西,就像下面这样的定义
val imm: InputMethodManager by lazy {
getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
}
1
2
3
lazy后面跟着的block只会在你第一次read这个imm的时候调用,以后读取imm会直接返回block保存的值。在需要追求启动速度的APP可以很好的使用。
1.3 扩展后的collections
kotlin提供了很多对collections和iterables的扩展,具体可以看下
我写的分析和使用collections。
1.4 Named 和 默认的函数参数
Named 函数参数和默认函数参数非常简单,但有时候可以帮我们省掉很多代码。特别是当构造函数有超过4个以上的参数时,可以指定默认几个默认参数,在调用的时候可以只提供一个参数。比如
class Presenter(
val okhttp: OkHttp = productionOkHttp(),
val picasso: Picasso = productionPicassoInstance()
) {...}
1
2
3
4
在调用的时候,我们不提供参数,那么默认参数会被使用
var prensenter = Presenter()
1
2.1 编译速度慢
大家在使用kotlin开发项目的时候应该有注意到了,主要还是因为kotlin会自动自动生成更多的代码,比如为属性生成get/set, 对比java会存在更多的方法数量。https://youtrack.jetbrains.com/issue/KT-6246,这篇博客有做分析
2.2 annotation processing的问题
我目前开发的项目使用了dagger,permissionsdispatcher,deeplinkdispatch,databinding,都需要使用kapt来做annotation proccessing,但是我已经碰到了好多次,kapt报的很奇怪的错误,有一次,我重构dagger的module时,报了一个蛋疼的问题,我以为我是dagger没用好,找了很多资料对比都没有解决,花了大概一天的时间,后面没办法只能clean project,但是奇怪的问题还在,后面我让application继承了DaggerApplication,clean下就可以。后面还是碰到好几次这样的问题,都是clean之后build就可以了,这个问题应该不只我一个人碰到,我想可能是kapt的一个bug, 我还是很相信google/JetBrains, 所以还是继续坚持使用kotlin开发项目。
2.3 没有命名空间
kotlin允许定义top-level的函数和属性,比如
//demo.kt
var a = "aa"
fun printlnA(){
println(a)
}
1
2
3
4
5
这可能是一个非常好的特性,但是也会有问题,比如在项目下面有两个甚至更多的printlnA方法,那么在调用的时候(特别是在阅读代码),很难区分方法来自哪个地方,除非你F3跳转到声明处。为了避免这个问题,你可以选择把printlnA方法移到一个object中,比如
object PrintlnHelper{
fun printlnA(){
println(a)
}
}
1
2
3
4
5
让我们来看下kotlin和java的调用方式
//kotlin
PrintlnHelper.printlnA()
//java
PrintlnHelper.INSTANCE.printlnA()
1
2
3
4
为了避免如上在Java中调用的怪怪的。。,可以使用@JvmStatic注解该方法
object PrintlnHelper{
@JvmStatic
fun printlnA(){
println(a)
}
}
1
2
3
4
5
6
通过上面的分析,对于有代码洁癖或者同时用Java和kotlin开发的项目,也是不够完美的,这个缺点是可以避免的,但是你需要花费一点时间去熟悉Kotlin
2.4 没有静态修饰语
还是像上面的问题,如果项目同时存在kotlin和Java,而且Java需要调用kotlin代码,看代码分析问题
//Java
public class View {
public static final int VISIBLE = 0x00000000;
public static final int INVISIBLE = 0x00000004;
public static View inflate(Context context, int resource) {...}
}
1
2
3
4
5
6
使用kotlin使用同样的功能,如下:
class View {
companion object {
@JvmField
val VISIBLE: Int = 0x00000000
@JvmField
val INVISIBLE: Int = 0x00000004
@JvmStatic
fun inflate(context: Context, resource: Int) {...}
}
}
1
2
3
4
5
6
7
8
9
10
下面是有@JvmField和没有的Java调用方式
// With annotations:
View.VISIBLE;
//Without annotations:
View.Companion.getVISIBLE();
1
2
3
4
其实这个问题也不是很严重的,但是对比Java还是多了个@JvmField, 但是kotlin新手或者容易忘记,使用@JvmField,这个缺点可以通过熟悉kotlin来避免
2.5 Java自动转换成kotlin带来的问题
Java自动转换成kotlin是个非常好的特性,但是也会带来问题。Javadoc原来的结构会被破坏掉,静态field和方法会转换成companion object中的普通声明,如果有Java代码调用这个类,就会出现点问题,除非你后面手动给这个转换后的companion object 添加上@JvmField和@JvmStatic。这是个不小的隐患,需要特别注意下。
2.6 会增加方法数量
过多的方法数量会导致编译速度变慢。kotlin通过闭包,内联函数等可以显著减少代码的总行数,但它可能也会增加编译后的方法数量。对于Android项目来说这肯定是一个不小的缺点。有很多原因会导致方法数量增加,但是最大的来源是kotlin实现属性。
kotlin不像Java可以直接访问field, 而是通过创建property的方式来访问。这是一个很好的特性,你可以自定义实现property的set/get,对比Java的set/get方法是个很大的进步。
但是这个是有代价的,对于val属性,kotlin自动生成backing field和getter函数来供java调用。public var属性会自动生成setter/getter函数。幸运的是private var属性已经有默认的setter/getter,需要不需要额外生成。所以这个时候你想想如果你定义了很多个public var和val属性,那么kotlin会帮你自动生成更多的函数,所以带来的后果就是方法数量会越来越多,导致编译速度变慢。
假如方法数量已经接近限制,不需要使用自定义setter的属性可以用@JvmField修饰,被@JvmField修饰的属性不会自动生成setter/getter函数,如下
@JvmField
var aMap: aMap? = null
1
2
2.7 “==”
在kotlin中,”==”和”equals”都是比较引用是否相等。如何项目中只有kotlin代码,那这个肯定是个非常好的特性,但是如果项目同时包含java和kotlin(比如:你是在旧的java工程基础上,用kotlin开发新功能),那么“==”很容易产生混淆和错乱。
kotlin的class默认是final, 如果想要能被继承,那么需要使用open 修饰,它的设计原则来自于
Effective Java
这种默认的设计原则,会导致第三方/未完成的sdk的大多数会是不可继承的,从提供者角度来说:它必须保证这个类是足够完整的,从使用者角度来说:这个类必须要提供我需要的所有东西,否则,我必须重写。当然提供者可以为这个类加上open来表示这个类是可以继承的,但是这是另外一种设计思维。
Roedy Green, How to Write Unmaintainable Code有提到:
给你的所有类设置为final。 毕竟,你完成了这个项目 - 当然没有人可以通过扩展你的class来改善你的工作。 这甚至可能是一个安全漏洞 - 毕竟,为什么不是java.lang.String final? 如果您的项目中的其他编程人员抱怨,请告诉他们您的执行速度提升
3.2 错误的使用运算符重载
kotlin允许对类的变量运算符进行重载,设想有下面的代码
var person3 = person1 + person2
1
作者:安卓机器人
来源:CSDN
原文:https://blog.csdn.net/ncuboy045wsq/article/details/74853107
版权声明:本文为博主原创文章,转载请附上博文链接!
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。