V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
sagaxu
V2EX  ›  Kotlin

Kotlin 入坑半年总结

  •  3
     
  •   sagaxu · 2017-07-08 00:43:01 +08:00 · 53478 次点击
    这是一个创建于 2730 天前的主题,其中的信息可能已经有所发展或是发生改变。

    半年前我在一个两年历史的后端 Java 项目中,尝试着引入了 Kotlin,半年过去,证明了当时的尝试是值得的。分享一下我的感受。

    优点

    • 无缝引入到现有 Java 项目,只看了半天文档就上手了,并且没有因为两种语言混合开发带来副作用。
    • 表达能力优于 Java,平均下来,在不影响可读性的情况下,大概可以比 Java 少写 1/3 的代码。
    • 增加特性的同时,没有降低性能,部分 benchmark 中还有微弱的性能提升,马儿跑得更快还吃的更少。
    • 适度的函数式编程支持,map-filter-fold 代替了一大堆 for-loop,简洁明了,代码中没有 map/list 构造工作干扰视线。
    • extension function 可以很方便的给现有的类扩充新的方法,而不用定义新类型,最常用的就是 TypeA.toTypeB()。
    • non-null 变量和 elvis 操作符,基本上消灭了 null 的烦恼,既不担心 NPE,又不用到处 if 判断是不是 null。
    • unchecked exception,可以自己决定在调用栈的某一层 catch 和处理,不必到处 try-catch 好麻烦。
    • val 和 var,在变量定义时决定它是否可以改变它的值,不能改变的值,是不用担心不小心覆盖的。
    • property 语法,不用让 IDE 自动生成 getter/setter 了,也不用 Lombok 自动合成这些方法了。
    • object,匿名对象信手拈来,并且编译器自动帮你搞成线程安全的 singleton。
    • delegate,和用它实现的 lazy evaluation,你甚至可以自行决定 lazy 求值在并发时的同步方式。
    • String Interpolation,"aaa$x"或者"aaa${x.y}"是不是很面熟?多行字符串也很方便。
    • when/let/apply/also/takeIf 等等操作,可以实现非常简洁的操控,直接消除掉 builder 设计模式了。
    • imutable 的 list/set/map,imutable 是个很好的约束工具,默认就该 imutable。
    • REPL,就是类似 jshell 的那个东西,很方便,也很实用,比如直接命令行访问某个类。

    缺点

    • $符号用于 String Interpolation,当前版本的 IDEA 无法正确处理 Value 注解中转义过的$。
    • spring-data 中 query builder 依赖的机制,目前不能方便的自动生成 Kotlin 的 Query Object。
    • 资料还是偏少,不过官网的文档差不多也够了,毕竟大部分库和框架,都是沿用的 Java 的。
    • IDEA 自动转换工具,把 Java 转换成 Kotlin,转换质量明显比我人肉转的要差的多。

    目前项目中一共有 200 多个 Java/Kotlin 代码文件,2/3 已经是 Kotlin 的了,估计半年后 Kotlin only 了。 下半年准备尝试用 coroutine 改造一下现有的多线程架构,3000 个线程已经限制到某些产品上的玩法了,异步回调的话又不太适合调用栈很深并且各种分支和跳转的业务,kotlin 的协程,可以直接 wrap 现有的异步的库,设计思路上很赞,充分利用现有的库。

    kotlinjs 虽然正式发布了,但是 runtime 太大,而且我已经用 coffeescript 了,就没有尝试。

    kotlin native 目前继续观望,也许明年会在合适的地方尝试一下,这也是个比较有趣的东西。

    31 条回复    2018-11-06 16:53:19 +08:00
    NullMan
        1
    NullMan  
       2017-07-08 00:59:09 +08:00
    既然是坑,那么永远就是坑。
    0nlyy0u
        2
    0nlyy0u  
       2017-07-08 01:16:23 +08:00
    对于新手来说,想学 android 还要再多学一门语言。
    twm
        3
    twm  
       2017-07-08 08:18:45 +08:00 via iPhone   ❤️ 2
    以为说的是 scala
    luban
        4
    luban  
       2017-07-08 09:04:24 +08:00 via iPhone
    感谢,最近想入坑 kotlin,上面说的 map,filter,java8 现在也有的
    aristotll
        5
    aristotll  
       2017-07-08 10:03:24 +08:00
    有些人除了嘲讽别人的学习经验就不能说点其他的吗
    nashxk
        6
    nashxk  
       2017-07-08 10:08:12 +08:00
    正在用 kotlin 改写 Android 项目,挺有意思的
    azh7138m
        7
    azh7138m  
       2017-07-08 10:11:36 +08:00 via Android   ❤️ 4
    你们上班怎么有这么多时间用来重构的。。。
    zwpaper
        8
    zwpaper  
       2017-07-08 11:00:12 +08:00 via iPhone
    能否问一下与 java8 的对比,有一些 java8 独有的特性,kotlin 是否支持?
    sagaxu
        9
    sagaxu  
    OP
       2017-07-08 11:49:56 +08:00
    @luban 的确,Java8 也有 map-filter,但是 Java 的 lambda 支持的比 Kotlin 差,函数式写法写起来罗嗦很多

    @zwpaper 哪些是 Java8 独有的特性?除了 multi catch,不记得有什么 Kotlin 不支持的又比较方便的 Java 特性

    @azh7138m 即便不用 Kotlin,也需要经常重构,把 bad smell 清理出代码库。迁移到 Kotlin 的时候,可以在比较大的版本发布时,每次夹带着转换掉几个 Java 文件。
    lowzoom
        10
    lowzoom  
       2017-07-08 12:06:04 +08:00
    3000 多个线程。。可以考虑用 AKKA
    Lispre
        11
    Lispre  
       2017-07-08 12:53:22 +08:00
    谢谢分享,我这边也已经在项目中实践了, 目前项目已经上线,考虑到人员的情况,新的项目决定还是不能太急了,慢慢来
    zwpaper
        12
    zwpaper  
       2017-07-08 12:59:22 +08:00 via iPhone
    @sagaxu 我的意思是对比 7 的特性,准备入坑 java,但是项目里说是用了大量 8 的特性,所以问问 kotlin 与 8 的对比

    顺便打听一下,新入坑 java,直接看 kotlin 可以吗?
    sagaxu
        13
    sagaxu  
    OP
       2017-07-08 13:09:37 +08:00
    @lowzoom 考量过 AKKA 和 vertx 还有 rxjava,这些库用来做底层通信协议是不错,处理复杂的业务逻辑的时候有点麻烦,状态个数比较多,不如 coroutine 方案来的直观和易于维护。而且迁移已有的阻塞型 Java 项目,用 coroutine 代价比较低,几乎不需要修改调用点之外的代码,之前甚至还考虑过用 Go 语言或者 elixir 重写,评估之后觉得成本太高,就等 Kotlin 1.2 发布了

    @Lispre 的确不宜操之过急,使用小众语言很容易遭到同事抵制,对 HR 也不友好
    sagaxu
        14
    sagaxu  
    OP
       2017-07-08 13:39:30 +08:00
    @zwpaper Java 7 和 8 的特性,在 Kotlin 面前都不值一提,Java 9 都赶不上,可能 Java 10 可以跟现在的 Kotlin 比比。不过新入 JVM 坑,不建议直接学 Kotlin,因为几乎所有资料都是围绕 Java 的,至少得看得懂 Java。
    nicevar
        15
    nicevar  
       2017-07-08 13:52:25 +08:00
    总结的不错,android 完全使用 kotlin 没啥问题了,好几个项目我都用了
    服务器方面一个后台管理的项目我在用 querydsl 遇到点问题,上层的一个模块还是完全用 java 的,其他的都用 kotlin 了
    notreami
        16
    notreami  
       2017-07-08 13:59:54 +08:00
    作为一个 Kotlin 的坚定反对派(可以理解为老旧派的反抗)。
    我就想问问:Kotlin 能带来什么?现代化编程带来的语法体验(写的爽,代码少)?还是安全检查?
    如果只是这些,我觉得 java9 或者第三方类不久之后肯定能带来这些特性。没必要专门去折腾另一门体系不完整的编程语言想替代 java 原生,然后来吹嘘下,比 java 原生爽(顺带唱衰下,分分钟 oracle 把 Kotlin 收购了)。
    我觉得有这时间折腾,还不如去学学 golang、javascript。全栈或者深入底层,都比这种今年火了下,可见的未来肯定只能打辅助的技能好( Scala 要不是绑上 Spark,一样是打辅助的)。
    notreami
        17
    notreami  
       2017-07-08 14:01:23 +08:00
    另外还有一个疑惑,android 代码里混入 java、Kotlin。构建工具是 gradle。然后 android 系是不是可以说,我们会三门编程语言:java8、Kotlin、Groovy
    aristotll
        18
    aristotll  
       2017-07-08 14:14:26 +08:00
    @notreami oracle 要收购也是收购 jetbrain. Java 必然会带来新特效 (但是 Java 有强的历史包袱)
    notreami
        19
    notreami  
       2017-07-08 14:37:03 +08:00
    @aristotll 我觉得 java 有强历史包袱这个点问题不大,因为即使上了 Kotlin 还是需要会 java。
    我更关注的点是,如果我们有一段时间,去掌握 Kotlin,还是去扩展技术栈掌握 golang 或 javascript,谁的价值更大。
    sagaxu
        20
    sagaxu  
    OP
       2017-07-08 14:43:38 +08:00
    @notreami 很遗憾,Java 9 并没有带来这些特性,第三方库也没法绕过语法限制。体系不完整是从什么角度评价的?

    实际上 go 和 js 我也用,python 和 php 也用,学一门语言只是一个周末的时间,反正不加班,这点儿时间我还是有的。

    在我正式开始用 Kotlin 的时候,搞安卓的都没几个人听说过 Kotlin 呢,今年突然火一把也是出乎我的意料。
    notreami
        21
    notreami  
       2017-07-08 15:21:33 +08:00
    @sagaxu 除了简洁,不觉得语法上限制会导致特性上的限制,而且完全可以造一段语法出来,比如注解、lambda。Kotlin 体系不完整指的是需要依赖 java 提供生态,而不是像 Scala 一样,完全可以自成生态(可以预想,以后 android 的开源库应该大部分都是纯 java 写)。
    go 或者 js 我提的是掌握,不只是它们的语法,还包括它们的生态库。这样拿来和 Kotlin 对比才有价值。

    把 Kotlin 引入除了语法糖,一直觉得没有什么意义。甚至还不如好好把 gradle 掌握了更有意义。


    未免不必要的麻烦。综上,我想表达是,需要掌握的技能栈很多,一门技能栈好上加好的价值大还是横向扩展技能栈的价值大。毕竟人的时间有限,除非你很聪明,比我学习和掌握一门技术所花时间短很多,那就当我没说过,毕竟你时间多。
    fly2never
        22
    fly2never  
       2017-07-08 16:57:06 +08:00 via iPhone
    方法数会增加多少? Android 上
    sagaxu
        23
    sagaxu  
    OP
       2017-07-08 16:57:32 +08:00
    @notreami 注解只能缓解,不能根治语法的不足,比如做 DSL 的时候,用 Java 就很麻烦,用 Kotlin 或者 ruby 就很简单。

    像这样一段 DSL,你用 Java 和注解可以很简单的实现吗?

    html {
    head {
    title { +"XML encoding with Kotlin" }
    }
    body {
    h1 { +"XML encoding with Kotlin" }
    p { +"this format is now type-safe" }

    /* an element with attributes and text content */
    a(href="http://jetbrains.com/kotlin") { +"Kotlin" }
    }
    }

    gradle 之所以用 groovy 做 build 的 DSL,也是因为语法表达灵活,现在 gradle 也支持 Kotlin 的 DSL 了,写法跟 groovy 的基本一致。


    Kotlin 不自己造轮子,充分利用 Java 的库,这正是它最聪明的地方,因为数据结构都是 Java 的,跟 Java 才没有 interop 的麻烦,Kotlin 调用 Java 或者 Java 调用 Kotlin,不用做数据结构的转换,也不用任何 wrap,就跟调用自己语言写的库一样方便。一段 JVM 字节码,是 Java 编译来的,还是 Kotlin 编译来的,没什么明显差异,所以原生不原生也无从谈起了。

    在技术的路线上,是深度更有价值还是广度更有价值,因人而异,同一个人的不同阶段答案也不同。
    wohenyingyu02
        24
    wohenyingyu02  
       2017-07-08 17:05:49 +08:00
    kotlin 可以直接调用 c 的动态库么,swift 就是因为无法直接调用还需要 oc 转一层,被我放弃了
    succlz123
        25
    succlz123  
       2017-07-09 00:32:59 +08:00
    代码混淆 需要作特殊处理么
    Miy4mori
        26
    Miy4mori  
       2017-07-09 04:48:15 +08:00 via iPhone
    只能说看起来很美吧,null safe 在和 java 库交互的时候就被废了一半,其他的特性也没有解决什么实质的问题,只是看起来舒服了一些。
    sagaxu
        27
    sagaxu  
    OP
       2017-07-09 12:01:31 +08:00
    @wohenyingyu02 Kotlin 在 JVM 调 C 库等同于 Java,Kotlin Native 只能调 C 库不能调 Java 库。

    @succlz123 JVM 字节码混淆工具,理论上不应该区分 Java 和 Kotlin 生成的字节码。

    @Miy4mori null safe 跟 Java 交互,调用 Java 的时候可以保证不会传不该 null 的 null 给 Java,获取 Java 返回值的时候可以写个!!后缀假定它是 nonnull 的,也可以假定它是可以 null 的,并不会损失 null safety。
    能写的舒服一点,读的舒服一点,顺带稍微减少点 bug,已经足够了。

    Kotlin 协程不知道算不算解决的实质问题,如果不用协程,我们新的需求要把 3000 个线程变成 30000 个,而用 akka 或者 vertx 这样的库又很难处理复杂业务逻辑,每次请求都要调用几十个服务,状态个数都超过 100 个了。如果不是有 Kotlin 协程,都计划用 Go 语言重写,放弃 JVM 了。
    williamwue
        28
    williamwue  
       2017-07-24 10:32:30 +08:00
    @sagaxu 写得很精彩,准备在项目中开始局部使用来学习一下
    hantsy
        29
    hantsy  
       2017-08-26 21:50:11 +08:00
    @sagaxu 帮忙 review 下我的问题: https://www.v2ex.com/t/386021

    现在应该不需要 AOP 也可以在 Spring 中用,后面再清理一下 Gradle BuildScripts 文件。Spring 5 中提供有 Kotlin 集成,如 BeanDefinitionDSL,RouterFunctionDSL, 基本项目配置可以用 Kotlin DSL 声明,可以不用 Annotation 了,我的 Sample 也不没有用 Spring Boot 启动程序了。
    darkread
        30
    darkread  
       2018-01-04 14:44:06 +08:00
    @notreami 我觉得你这个说法很奇怪。你 golang 可以用 java 库么?你的 js 可以用 java 库么?都不行。你说转 golang,那你转吧,Go 是很火,你想清楚要造多少轮子,再说,有没有是一回事,好不好是另外一回事。java 有 Spring,Go 有 GoBee,但是事实上,GoBee 有很多问题。你愿意一个个去尝试,就去吧,不要误导别人啊。
    kotlin 可以啊,我有简便的 null 检查,不需要写丑陋的 helpler,为什么不用?我 lambda 是一类公民为什么不用?
    说对了,就是爽!就是代码少!你等 java9 来了,你用么? Java9 有 kotlin 好用么?
    等 Oracle 收购?你做梦吧,kotlin 是 gg 宣布支持的第三个 Android 顶级语言,为什么不就是为了对抗 Oracle 向 GG 收取 java 收取费么?会把对抗武器卖给敌人?
    winniewhwh
        31
    winniewhwh  
       2018-11-06 16:53:19 +08:00
    Java 要收费了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2856 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 08:23 · PVG 16:23 · LAX 00:23 · JFK 03:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.