前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kotlin京东业务实战 | 强大又简洁的JVM语言

Kotlin京东业务实战 | 强大又简洁的JVM语言

作者头像
京东技术
发布2018-08-08 17:42:17
1.6K0
发布2018-08-08 17:42:17
举报
文章被收录于专栏:京东技术京东技术

作 者 简 介

赵振华——京东商城资深工程师

9年以上开发经验,熟悉主流移动开发框架,热衷于探索新技术,曾负责过店铺、JDReact架构等项目的开发工作,目前专注于京东App领券中心频道开发,以及移动端技术难点攻克和新技术调研实施。

2011年JetBrains推出Kotlin项目,这是一个面向JVM的新语言,主要是解决Java之前被诟病已久的问题,而且积极借鉴了 Scala、Ruby等新语言在开发效率和简洁性上的优势。

2017年Google开始力推Kotlin,在I/O大会上谷歌宣布Kotlin正式成为Android官方支持开发语言。

2018年4月18号《JAVA编程思想》作者Bruce大神给6967名京东兄弟分享了kotlin语言,认为kotlin为未来语言发展的趋势之一。

Kotlin已经越走越近,抱着“为了让移动开发更简单”的理念,让Kotlin在京东业务中落地。

>>>> Kotlin简介

Kotlin是一门运行在JVM之上的语言,由Jetbrains创建。Kotlin是一门非常简单的语言,其主要目标之一就是提供强大语言的同时又保持简单且精简的语法。

>>>> 为什么选择 Kotlin

  • 简洁:这一点对于Android来说非常重要。项目所需要的库应该尽可能的小。Android对于方法数量有严格的限制,Kotlin依赖库只额外增加了大约6000个方法。同时用Kotlin开发的项目,方法数量也会大幅减少。
  • 安全:Java最大的一个问题就是null。如果没有对变量或是参数进行null判断,那么程序当中就有可能抛出大量的NullPointerException,然而在编码时这些又是难以检测到的。Kotlin使用了显式的null,这会强制我们在必要时进行null检查。
  • 互操作:Kotlin可与Java语言无缝通信。这意味着我们可以在Kotlin代码中使用任何已有的Java库;因此,即便这门语言还很年轻,但却已经可以使用成百上千的库了。除此之外,Kotlin代码还可以为Java代码所用,这意味着我们可以使用这两种语言来构建软件。你可以使用Kotlin开发新特性,同时使用Java实现的其他部分代码。
  • 工具友好:可用任何 Java IDE 或者使用命令行构建,包括常用的IntelliJ IDEA,Android Studio,Eclipse,命令行等。

对比其他语言,Kotlin语法和Java很像,非常容易上手,推荐以循序渐进的方式开发项目;由于项目中允许同时存在Java和Kotlin代码文件,并且允许Java与Kotlin互调,使得开发者可以很方便的在已有项目中引入Kotlin;新模块用Kotlin,稳定模块勿需用Kotlin重写。

>>>> Kotlin的一些特性

Kotlin拥有大量非常打动人心的特性,这里无法一一进行介绍,不过我们来看一下其中最为重要的一些。

>>>> Null安全

如前所述,Kotlin是null安全的。如果一个类型可能为null,那么我们就需要在类型后面加上一个?。这样,每次在使用该类型的变量时,我们都需要进行null检查。比如说,如下代码将无法编译通过:

代码语言:javascript
复制
var artist: Artist? = null?
artist.print()

第2行会显示一个错误,因为没有对变量进行null检查。

Null曾经被戏称为“十亿美金的错误”,Null虽然好用,但是导致很多错误的元凶往往都是它。在Kotlin中,编译器是可以识别你的引用是否是null,进而提醒你。默认kotlin中所有的对象都是不为Null的。

>>>> 数据类

在Java中,如果想要创建数据类或是POJO类(只保存了一些状态的类),我们需要创建一个拥有大量字段、getters与setters的类,也许还要提供toString与equals方法:

代码语言:javascript
复制
public class Artist {
    private long id;
    private String name;
    private String url;
    private String mbid;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getMbid() {
        return mbid;
    }

    public void setMbid(String mbid) {
        this.mbid = mbid;
    }

    @Override public String toString() {
        return "Artist{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", url='" + url + '\'' +
                ", mbid='" + mbid + '\'' +
                '}';
    }
}

在Kotlin中,上述代码可以写成下面这样:

代码语言:javascript
复制
data class Artist (
    var id: Long,
    var name: String,
    var url: String,
    var mbid: String)

使用一行代码创建一个包含 getters、 setters、 equals()、 hashCode()、 toString() 以及 copy() 的 POJO。

>>>> 互操作

Kotlin提供了一些非常棒的互操作特性,这对于Android开发帮助非常大。其中之一就是拥有单个方法的接口与lambda表达式之间的映射。例如下面这个单击监听器:

代码语言:javascript
复制
viewHolder.mCouponItemBottom?.setOnClickListener(
    object : View.OnClickListener {
      override fun onClick(v: View) {
        Toast.makeText(mContext, "Click", Toast.LENGTH_LONG).show()
      }
    }
)

可以写成这样:

代码语言:javascript
复制
viewHolder.mCouponItemBottom?.setOnClickListener {
    Toast.makeText(mContext, "Click", Toast.LENGTH_LONG).show()
}

>>>> Lambda表达式

Lambda表达式会极大程度的精简代码,借助于Lambda表达式,我们可以做到之前无法实现或是实现起来非常麻烦的事情。借助于Lambda表达式,我们可以以一种更加函数式的方式来思考问题。Lambda表达式其实就是一种指定类型,并且该类型定义了一个函数的方式。

lambda的标准形式基本声明满足三个条件:含有实际参数,含有函数体,以上内部必须被包含在花括号内部。

代码语言:javascript
复制
val sum = { x: Int, y: Int -> x + y }

>>>> Kotlin编译分析

Kotlin代码比Java的简洁,更易于编写维护,所以我们认为转换是值得的。 但很多开发者都担心Kotlin编译可能没有Java快,影响开发效率,反而得不偿失。

>>>> 过程分析

上图是Java编译器的编译过程,Kotlin和Java的编译过程是很相似的,区别在于Kotlin与Java相比重要的细节在编译后端(目标代码生成)环节。

Kotlin编译器在目标代码生成环节做了很多类似于Java封装的事情,比如自动生成Getter/Setter代码的生成、Companion转变成静态类、修改类属性为final不可继承(open修饰即可继承)等等工作。

Kotlin将我们本来在代码层做的一些封装工作转移到了编译后端阶段,使得语言更加简洁。

>>>> 速度分析

在相同gradle版本,相同设备的情况下,通过重复执行gradle指令,对几个不同的编译场景进行了基准测试,对比Kotlin和Java的编译时间。发现Java在clean构建比Kotlin 快10-15%,增量编译时Kotlin比Java编译速度略快。对于大多数开发人员来说,更常见的情况是增量编译,Kotlin对增量编译进行了大量改进,保证了编译速度。

由此可见,开发人员不需要担心Kotlin的编译时间,Kotlin的编译速度和Java一样快。

>>>> 京东业务实现

>>>> 环境配置

1、安装 Kotlin 插件

Android Studio3.0(preview)版本开始将内置安装 Kotlin插件。如果你正在使用的是早期版本, 需要通过File | Settings | Plugins | Install JetBrains plugin…搜索并安装Kotlin插件。

2、Jdlib工程中配置 Kotlin

新增 apply plugin: ‘kotlin-android’ 及其依赖。

代码语言:javascript
复制
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
代码语言:javascript
复制
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
代码语言:javascript
复制
dependencies {
        classpath "org.jetbrains.kotlin:kotlin-android-extensions:1.2.41"
    }
代码语言:javascript
复制
dependencies {
        ...
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }

3、插件工程中配置 Kotlin

配置方式与Jdlib相同,注意需要将compile修改为provided,防止类库重复引用。如果不配置,插件代码不能打到apk中,调用时报ClassNotFoundException异常。

代码语言:javascript
复制
provided "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"

4、添加混淆配置

如果调试Kotlin代码,总是报ClassNotFoundException异常,或者NoSuchMethod异常,你要考虑加入混淆配置。缺失混淆配置,Kotlin类库代码会被优化掉,编译正常,但无法运行。

代码语言:javascript
复制
# Kotlin
-dontwarn kotlin.**
-keep class kotlin.** {*;}
-keepclassmembers class **$WhenMappings {
    <fields>;
    <methods>;
}

>>>> 业务实现

1、业务重写

将整个模块改为Kotlin语言实现,修复语法方面的编译错误。Android Studio提供将Java转为Kotlin的插件,可以转换大部分代码。

常见编译问题:

a、代码编译出错,定义变量时,没有赋初始值,变量可以为空,需要加?修饰符

代码语言:javascript
复制
var mCouponItemLayout: RelativeLayout
var mCouponItemTop: LinearLayout
var mCouponIcon: SimpleDraweeView
var mCouponName: TextView
var mCouponItemTopTv1: TextView
var mCouponItemTopTv2: TextView
var mCouponItemMiddle: LinearLayout

以下为修改后的代码:

代码语言:javascript
复制
var mCouponItemLayout: RelativeLayout? = null
var mCouponItemTop: LinearLayout? = null
var mCouponIcon: SimpleDraweeView? = null
var mCouponName: TextView? = null
var mCouponItemTopTv1: TextView? = null
var mCouponItemTopTv2: TextView? = null
var mCouponItemMiddle: LinearLayout? = null

b、代码编译出错,变量可以为空时,使用变量需要加?修饰符,自动判断是否为空,防止出现空指针异常

代码语言:javascript
复制
viewHolder.mCouponItemValueDiscount.text = entity.quota
viewHolder.mCouponItemValuePrice.text = entity.minOrderAmount

以下为修改后的代码:

代码语言:javascript
复制
viewHolder.mCouponItemValueDiscount?.text = entity.quota
viewHolder.mCouponItemValuePrice?.text = entity.minOrderAmount

c、代码编译出错,由于FontsUtil的参数有@NonNull标签,需要保证只有在确保变量不是null的情况下才能这么调用,否则它会抛出异常

代码语言:javascript
复制
FontsUtil.changeTextFont(viewHolder.mCouponItemMoneyTag, FontsUtil.MULTI_BOLD)
FontsUtil.changeTextFont(viewHolder.mCouponItemValueDiscount, FontsUtil.MULTI_REGULAR)

以下为修改后的代码:

代码语言:javascript
复制
FontsUtil.changeTextFont(viewHolder.mCouponItemMoneyTag!!, FontsUtil.MULTI_BOLD)
FontsUtil.changeTextFont(viewHolder.mCouponItemValueDiscount!!, FontsUtil.MULTI_REGULAR)
2、运行调试

编译成功后进行代码调试,修改运行时异常问题,可以正常使用debug工具,Kotlin模块与Java模块互相直接调用,显示效果和交互效果与Java模块没有差别。

Kotlin语言提供了类型的自动判断,自动拆装箱,字符串拼接,lambda表达式,空判断等一系列功能,功能精简了很多,语法与js有相似,同时去掉了findViewById(),省去了很多if try等语句,业务代码量减少很多。

统计业务模块的Java实现和Kotlin实现的代码量,不包含xml布局文件,代码量减少超过20%;代码减少最多的为pojo类,减少比例甚至超过80%;业务逻辑代码减少10%,同时代码会更加简洁直观,有助于提高代码可维护性。

3、ABTest上线

由于业务量级比较大,为防止新技术对业务稳定性产生影响,计划通过Java实现代码,Kotlin 实现代码两套代码并存,使用ABTest方式逐渐放量,待稳定后切到Kotlin

Kotlin在设计上避免了常见的编程错误,从而减少了应用程序崩溃和系统故障。此外,由于Kotlin 是快速失败机制,可以立即报告任何可能导致失败的问题。因此 Kotlin 在降低应用崩溃率上有很大作用,非常值得期待!

>>>> 常见问题

  • 环境配置出错,出现无法编译或编译正常但apk中无kotlin代码,运行时报kotlin代码找不到; 解决方法:在插件代码中配置kotlin环境,在gradle中增加classpath,compile等,如果不配置环境,kotlin代码不会做编译;
  • 正常出包后,无法运行,调试kotlin代码,总是报Intrinsics的ClassNotFoundException异常,通过反编译分析apk,发现丢失部分代码; 解决方法:在jdlib代码中,加入遗漏的kotlin-android-extensions依赖,同时修改proguard,解决ClassNotFoundException异常;
  • 运行过程中报checkExpressionValueIsNotNull NoSuchMethod异常,分析apk与kotlin源码,发现kotlin中Intrinsics类部分方法打包后丢失; 解决方法:在主站代码中配置属性方法混淆,保证kotlin类中属性方法全部不做混淆优化;
  • 为了保证插件包大小,并且与主站代码不重复,引用类库时使用provided; 解决方法:使用provided引入类库,在编译时使用,最终不会被编译到apk;后期将配置环境放到aura中更方便。

>>>> 使用案例

Pinterest

Pinterest 已成功将 Kotlin 引入了他们的应用程序,每个月有 1 亿 5 千万人使用。

Gradle

Gradle 正引入 Kotlin 作为编写脚本的语言。

Evernote

Evernote 最近 将 Kotlin 整合到了他们的 Android 客户端。

Uber

Uber 团队使用 Kotlin 来构建内部工具。

Corda

Corda是一个开源分布式分类账号平台,由各大银行提供支持,完全由 Kotlin 构建。

Coursera

Coursera Android 应用程序部分用 Kotlin 编写。

Pivotal

Spring 采用 Kotlin 的语言特性来提供更简洁的 API

Atlassian

Trello Android应用程序中的所有新代码都用 Kotlin

>>>> 反馈与建议

  • 邮箱:zhaozhenhua8@jd.com

>>>> 参考资料

  • 对话《JAVA编程思想》作者Bruce 地址: http://tech.jd.com/course/toDetail?courseId=710
  • kotlin中文网站 地址:https://www.kotlincn.net
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-08-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 京东技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 作 者 简 介
  • >>>> Kotlin简介
    • Kotlin是一门运行在JVM之上的语言,由Jetbrains创建。Kotlin是一门非常简单的语言,其主要目标之一就是提供强大语言的同时又保持简单且精简的语法。
      • 1、业务重写
      • 2、运行调试
      • 3、ABTest上线
  • >>>> 为什么选择 Kotlin
  • >>>> Kotlin的一些特性
  • >>>> Null安全
  • >>>> 数据类
  • >>>> 互操作
  • >>>> Lambda表达式
  • >>>> Kotlin编译分析
  • >>>> 过程分析
  • >>>> 速度分析
  • >>>> 京东业务实现
  • >>>> 环境配置
  • >>>> 业务实现
  • >>>> 常见问题
  • >>>> 使用案例
  • >>>> 反馈与建议
  • >>>> 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档