开发者社区> 问答> 正文

[@talishboy][¥20]kotlin给我们带来什么便利了

当前如果全面使用kotlin来代替java,能够给我们带来什么便利呢

展开
收起
Nebula 2018-12-15 22:35:40 3667 0
3 条回答
写回答
取消 提交回答
  • 好处很多啊
    1) 更多的编程方式,支持OO、过程式和FP
    2) 空安全,更优雅的解决了NPE
    3) 与Java无缝集成,支持双向的调用
    4) 支持操作符重载
    5) 采用Any作为基类解决了装箱和拆箱的问题,可以统一为Int/Long
    6)没有Checked Exception
    7) 支持侵入式编程
    8) 支持参数默认值

    2019-07-17 23:22:03
    赞同 展开评论 打赏
    1. 优点
      kotlin提供了很多好的特性,比如:null安全检测,属性访问,unchecked exceptions, publication有更详细的介绍。

    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

    1. 缺点
      虽然kotlin非常强大,但它毕竟不是完美的。它也会有一些可能未来会解决的缺点。

    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开发新功能),那么“==”很容易产生混淆和错乱。

    1. 设计原则
      3.1

    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
    版权声明:本文为博主原创文章,转载请附上博文链接!

    2019-07-17 23:22:03
    赞同 展开评论 打赏
  • 语法糖更多吧

    2019-07-17 23:22:03
    赞同 展开评论 打赏
问答分类:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
深入浅出Dart 立即下载
低代码开发师(初级)实战教程 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载