将APP变成使用100%Kotlin的总结

qn0041 7年前
   <p>我已经关注Kotlin的发展有一段时间了,Kotlin是一个基于 JVM ,兼容 <a href="/misc/goto?guid=4959649700166527629" rel="nofollow,noindex">Java</a> 的新的编程语言。随着Kotlin版本1.0.2的发布,带来的增量编译和在标准库大量减少的方法数量,我开始渴望在项目中使用它。</p>    <p>我是Keepsafe应用锁app的首席工程师,该app和大多android应用app都是通过java语言开发的。Java有很多现代编程语言的不足的地方,尤其是Android支持Java 7的版本。为了解决这个问题,通常是使用类库,例如为了lambdas和关闭资源使用Retrolambda,为了不可变集合和有效函数使用Guava,为了view的绑定使用ButterKnife或者为了函数式编程使用ReactiveX。但是,这些类库也有很多缺点,你依赖的每个类库给APK添加方法,Retrolambda时常会增量构建失败。</p>    <p>即使有这些库,Java代码也很冗余。在90年代Java的设计者认为,你的代码要经过大量的设计是个不错的主意,但今天显然是不必要的。Kotlin提供了一个经过深思熟虑的语法和广泛的标准库,消除许多存在于Java中的痛点。因此,在多天的努力中,我将整个App Lock应用程序锁定app的代码转换成Kotlin。这里是我在转换过程中的想法和总结。</p>    <h2><strong>Kotlin vs Java in App Lock</strong></h2>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/54b404407da2268f5fb39fb9b4b7c481.png"></p>    <p>在 <strong>App Lock</strong> 转换为 <strong>Kotlin</strong> 后方法的统计。从dexcount gradle这个插件得到的。</p>    <p>通过它的标准库添加的方法数量,是大家提高转换成Kotlin关注的地方。由于像support library和GMS这些类库,会提高许多app在 <a href="/misc/goto?guid=4959676865080574261" rel="nofollow,noindex">Dex 方法数量限制</a> 上的风险。在重写前后,我使用dexcount gradle插件来对方法分解。最终的结果是,总的方法数在proguard之后,从5491变成4987下降了10%(不包括GMS和appcompat的统计)。代码数从java的12371行变成Kotlin的8564行,减少了30%。 <strong> </strong></p>    <p><strong>app从Java转成Kotlin,总的方法数减少了10%,总的代码行数减少了30%。</strong></p>    <p>方法数减少的结果既是Kotlin本身是一种更加简洁的语言导致的,同时也证明很多以前在Java中使用质量不错的库将不再需要的事实。</p>    <p><strong>Retrolambda</strong></p>    <p>Retrolambda 为每一个添加多个方法的lambda自动生成一个匿名类。Kotlin有用到一个lambda可以无需增加任何额外的方法来内联方法。</p>    <pre>  public inline fun <T> T.apply(block: T.() -> Unit): T {       block(); return this   }</pre>    <p>例如,非常有用的标准库函数 <a href="/misc/goto?guid=4959717376305705390" rel="nofollow,noindex">应用</a></p>    <p>通过这种方式调用</p>    <pre>  myObject.apply { /* modify myObject */ }</pre>    <p>你在定义一个lambda函数调用时,没有匿名类生成,由于这个调用,没有额外的方法被添加,也没有发生内存分配。事实上,应用函数本身,就像大多数在Kotlin标准库内部关联函数,不会导致一个方法在编译代码过程中被添加。</p>    <p><strong>Guava</strong></p>    <p>Guava整体被具有更易于使用的额外优势的Kotlin标准库所代替。Big Guava ComparisonChain可以被kotlin.comparisons函数用一些字符代替。</p>    <pre>  <span style="font-size:18px;">// Guava        ComparisonChain.start()        .compareTrueFirst(lhs.isActive(), rhs.isActive())        .compare(lhs.lastName(), rhs.lastName())        .compare(lhs.firstName(), rhs.lastName())        .result();        //Kotlin        compareValuesBy(lhs, rhs,        {it.active},{it.lastName},{it.firstName})</span></pre>    <p>Guava null-safety可选的类在 <a href="/misc/goto?guid=4959717376395581612" rel="nofollow,noindex">Kotlin里面被创建</a> 。</p>    <pre>  // Guava  return Optional.of(value).or(defaultValue);    // Kotlin  return value ?: defaultValue</pre>    <p>Guava的lazy fields和前提条件类也被 <a href="/misc/goto?guid=4959717376473322596" rel="nofollow,noindex">Kotlin</a> 的标准库所代替</p>    <pre>  <span style="font-size:18px;">// Guava        private Supplier lazyField = Suppliers.memoize(        () -> "value");        public String getField() {        return lazyField.get();        }          // Kotlin        val field bylazy{"value"}        // Guava        Preconditions.checkNotNull(value, "error %s", arg);        // Kotlin        checkNotNull(value){"$arg"}</span></pre>    <p>几乎所有的Guava的集合类都在Kotlin中存在。即便Guava所有的这些功能,整个Kotlin标准库仍单独比Guava小。</p>    <p><strong>ButterKnife</strong></p>    <p>ButterKnife依然被用于Kotlin中,但是 <a href="/misc/goto?guid=4959717376560255519" rel="nofollow,noindex">Kotlin Android Extensions</a> 提供了一种更加简洁的方法来绑定view。也存在其他的解决方案如Kotterknife和Anko,但是我发现当前通常的xml布局使用Kotlin Android Extensions是处理view最好的方式。Kotterknife比extensions需要更多的引用。Anko会添加大量的方法,而且它的DSL往往较为复杂并且比XML性能低。</p>    <p><strong>RxJava</strong></p>    <p>RxJava也是非常棒的,我在App Lock的很多地方使用它。但由于Java的Android上并没有对集合功能的方法,我有时会用RxJava作为替代品。 </p>    <pre>  Observable.from(collection)      .filter(it -> it.isActive())      .map(it -> it.size())      .reduce((it, sum) -> it + sum)      .toBlocking().single();</pre>    <p>在Kotlin里可以被替换成:</p>    <pre>  collection.filter { it.isActive() }            .map { it.size() }            .reduce { it, sum -> it + sum }</pre>    <h2><strong>Kotlin入门</strong></h2>    <p>如果你已经有一定java基础,学习Kotlin很容易。你可以通过 <a href="/misc/goto?guid=4958878434725873896" rel="nofollow,noindex">Kotlin Koans online</a> 学习,使用 <a href="/misc/goto?guid=4958878434725873896" rel="nofollow,noindex">reference documentation</a> 编写。Jake Wharton也提供了很多 <a href="/misc/goto?guid=4959717376687411330" rel="nofollow,noindex">Kotlin有用的语法功能的说明</a> 。</p>    <p>关于Kotlin最好的一部分是它能够在Java和Kotlin直接相互调用。所以你并不需要你的整个代码库一次转换。我建议你最开始的时候,从一个重写的单独文件开始。IntelliJ具有自动从Java转换成Kotlin的功能,但是它经常会产生不正确的代码。因此,更好的做法是从一个草稿开始,直到你对编程语言很熟悉的时候。</p>    <p>一旦你具备一定基础知识后,我建议选择一些依赖现有的Java代码,并将其转化为Kotlin。像Android上面的fragment的activity的ui代码是一个很好的实践的地方。选取一个没有依赖的类,允许你只关注你的工作代码,无需担心任何接口正在发生变化。保持Kotlin的开放,使你可以快速的处理正在编译时产生的语法或者标准库相关问题。你也可以开始就选择Kotlin编写,来代替把Java转换成Kotlin。但是我发现从被转换的代码选取的不太明显的语法比试图从一张白纸弄明白更加容易。大多数情况下,自动转换是一个不错的选择,它出问题的地方通常也很容易解决。</p>    <p>当你正在学习Kotlin时,需要明确目的是避免项目不堪重负。如果你还没有使用像MVP或者MVVM,不用担心试图在同一时间学习。不要担心找不到可用的Kotlin库。只关注在你所知道的关于Java和Kotlin转换的知识。如果您仍然有痛点,那么你可以添加更多的库或设计模式。</p>    <h2><strong>你应该将你的代码库一次性替换吗?</strong></h2>    <p>当你在你的代码库里面提供了很多Kotlin后,你必须决定是否一次全部转换成Kotlin,或者把它变得更慢。幸运的是,Kotlin兼容Java,两者相通。你可以同时将单独的类转换,也可以让两种语言一起并存运行。</p>    <p>对于大的代码库,将所有的转换成一个正式版本会需要大量的工作量。在Keepsafe主要的app里面,截止至写这篇文章时,大约15%的代码是Kotlin.在该应用程序,如果我们不得不明显更改一个Java类,我们通常会将类转换为Kotlin,我们也正在为此努力。这让我们可以稳定的提高代码库,而不会在新特性上减慢我们的工作。</p>    <p>但是,如果你的项目足够小,你可以转换到100%Kotlin,这是值得考虑的。当你不必维护Java的兼容性,可以简化您内部API,并删除了很多我前面谈到的库。您可以将静态工具类转换成扩展功能,并采取Kotlin更强的类型推断的优势。</p>    <h2><strong>最后的思考</strong></h2>    <p>Kotlin是一种伟大的编程语言,是对Java的巨大改善。将App Lock转换成Kotlin,让app更快,更小,相比之前更少的bug。Kotlin语言现在已经足够成熟,不管在任何一种工具,语言,或标准库,没有重要的功能缺失。如果你想知道现在是否尝试Kotlin或者你应该等待一段时间,我可以告诉你,现在Kotlin准备在全职生产使用。如果你使用Android或其他Java环境都是Kotlin可能的工作的地方,你应该为自己尝试一下Kotlin。</p>    <p> </p>    <p> </p>    <p> </p>    <p>来自:http://blog.csdn.net/u011176685/article/details/52673390</p>    <p> </p>