把一个Java应用程序转变为Kotlin,编译时间要多长时间?

写在文前

正文将显示在Android中会碰到的其实难点,况兼应用Kotlin怎么去消除它们。一些Android开采者在拍卖异步、数据库恐怕管理Activity中极度冗长的listener时意识了比比较多的主题材料。通过两个个切实地工作的场馆,我们单方面解决难点一边念书Kotlin的特色。

第12章 使用 Kotlin 集成Gradle 开发


这是关于Kotlin的一多级文章。分为八个部分。
第二盘部探讨了从Java调换来Kotlin。第二片段是自己对Kotlin的思想。

火速上手

一经不领会如何在Kotlin中写一个一定轻巧的Java表明式。这里有叁个简洁明了的路子,就是在AndroidStudio的Java文件中编辑一段代码,然后将其粘贴到kt文件中,它会自动转变为Kotlin。

《Kotlin极简教程》正式上架:

点击这里 > 去京东店铺购销阅读

点击这里 > 去Tmall购买阅读

在头里的稿子中, 小编谈谈了把Android 应用从Java 百分百转移为Kotlin 。
Kotlin代码比Java的简练,更便于维护,所以自身以为调换是值得的。
但有些人不想试用Kotlin,因为他俩顾虑它编写翻译大概未有Java快。
那几个关怀点相对是未可厚非的,假使变得编写翻译异常慢,未有人愿意转变他们的代码。
所以,让大家编写翻译Lock
App试一下
,然后作者把它调换到Kotlin。 笔者不会猜测比较一行代码的编写翻译速度;
相反,笔者将尝试回答将代码从Java转变为Kotlin是还是不是会影响其全部构建的光阴。

Kotlin优势

  1. 它更是易表现:那是它最珍视的帮助和益处之一。你能够编写少得多的代码。

  2. 它尤其安全:Kotlin是空安全的,约等于说在我们编写翻译时代就管理了各类null的景观,防止了实行时那么些。你可以省去相当多调治将养空指针卓殊的流年,消逝掉null引发的bug。

  3. 它能够扩张函数:那代表,纵然大家从没权力去拜谒那么些类中的代码,大家也得以扩大那个类的更加多的特点。

  4. 它是函数式的:Kotlin是依赖面向对象的言语。不过就疑似其余比很多当代的语言那样,它利用了广大函数式编制程序的概念,比方,使用lambda表明式来更方便地消除难点。在那之中三个很棒的特色便是Collections的管理格局。小编稍后会开展介绍。

  5. 它是可观互操作性的:你能够三番五次接受全部用Java写的代码和库,以致足以在二个体系中利用Kotlin和Java三种语言混合编制程序。一行Java一行Kotlin,别提有多罗曼蒂克了。

特别谢谢您贴心的读者,我们请多辅助!!!有别的难题,招待任何时候与自己沟通~


鉴于 Kotlin 具有足够的意义,如一等函数和强大方法等,由此它能够保留和改进Gradle 创设脚本的最棒部分——包涵简明的申明式语法以致轻便构建 DSL 的力量。

Gradle 团队与 Kotlin 团队紧凑协作,为 Gradle 开辟了新的基于 Kotlin
脚本的创设配置语言,大家称为 Gradle Script Kotlin,帮助接收 Kotlin
编写创设和布局文件。同时,还扶植在 IDE
中落到实处活动完毕和编写翻译检查等职能。有了Gradle Script Kotlin,我们能够运用
Kotlin 来写配置文件,就跟写普通代码相像。

作者们在前头的章节中,已经有超级多演示项目接纳了 Gradle 来创设我们的 Kotlin
工程。本章大家将系统地来介绍一下应用 Kotlin 集成Gradle 开垦的相关内容。

自己如何测验创设时间

自身写了贰个shell来重新实施gradle。 全数测验延续进行拾二次。
该项目标种种场景从前clean,并选取Gradle daemon ,daemon以前甘休二次。
本文中的全数测验都在运作于3.4 GHz的AMD Core
i7-6700上,使用32GB的DD大切诺基4内部存款和储蓄器和Samsung850 Pro SSD。 源代码是用Gradle
2.14.1营造的。

详细实例

1. 易展现和简洁性

透过Kotlin,能够更便于地防止模版代码,因为超越50%的非凡气象都在语言中暗许覆盖实现了。

比方,在Java中,借使大家要优质的数据类,我们供给去编写(最少生成)那些代码:

public class User{
    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 "User{" +
          "id=" + id +
          ", name='" + name + ''' +
          ", url='" + url + ''' +
          ", mbid='" + mbid + ''' +
          '}';
    }
}

作者们在不利用第三方框架的底工上,需求多量的set get方法和复写底子措施。

而选用Kotlin,我们只必要经过data关键字:

data class User(
    var id: Long,
    var name: String,
    var url: String,
    var mbid: String)

其一数据类,它会自动生成全部属性和它们的访谈器, 并自动生成相应的
equals、hashcode、toString 方法。

立此存照,我们证实一下:

首先创立贰个kt文件,新建三个简约的User类:

data class User(var name: String)

那时候在命令行使用kotlinc编写翻译,获得一个class文件,反编译成Java文件,可以见见:

public final class User {
   @NotNull
   private String name;

   @NotNull
   public final String getName() {
      return this.name;
   }

   public final void setName(@NotNull String var1) {
      Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
      this.name = var1;
   }

   public User(@NotNull String name) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      super();
      this.name = name;
   }

  // 解构声明
   @NotNull
   public final String component1() {
      return this.name;
   }

   @NotNull
   public final User copy(@NotNull String name) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      return new User(name);
   }

   // $FF: synthetic method
   // $FF: bridge method
   @NotNull
   public static User copy$default(User var0, String var1, int var2, Object var3) {
      if((var2 & 1) != 0) {
         var1 = var0.name;
      }

      return var0.copy(var1);
   }

   public String toString() {
      return "User(name=" + this.name + ")";
   }

   public int hashCode() {
      return this.name != null?this.name.hashCode():0;
   }

   public boolean equals(Object var1) {
      if(this != var1) {
         if(var1 instanceof User) {
            User var2 = (User)var1;
            if(Intrinsics.areEqual(this.name, var2.name)) {
               return true;
            }
         }

         return false;
      } else {
         return true;
      }
   }
}

真情证实在kotlin中 data 修饰符 = java中 private + getter + setter +
toString + equals + hashCode

2. 空安全

当大家采纳Java开采的时候,假使我们不想遭受NullPointerException,我们就要求在历次使用它前面,不停地去剖断它是还是不是为null。

而Kotlin是空安全的,大家由此二个安全调用操作符?来鲜明地钦命叁个目的是还是不是能为空。

大家能够像那样去写:

// 这里不能通过编译. User对象不能是null
var notNullUser: User= null

// User可以是 null
var user: User? = null

// 无法编译, user可能是null,我们需要进行处理
user.print()

// 只要在user != null时才会打印
user?.print()

// 使用Elvis操作符来给定一个在是null的情况下的替代值
val name = user?.name ?: "empty"

/** 
如果user为可空类型,又一定要调用它的成员函数和变量,可以用!!操作符
两种可能,要么正确返回name,要么抛出空指针异常
当user为null,你不想返回null,而是抛出一个空指针异常,你就可以使用它。
*/
var name = user!!.name

3. 恢弘方法

笔者们能够给任何类增多函数(View,Context等)。比起Java的世襲机制,特别精简和古雅。比如,我们得以给fragment扩充七个突显toast的函数:

fun Fragment.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) { 
    Toast.makeText(getActivity(), message, duration).show()
}

我们现在得以这么做:

fragment.toast("Hello world!")

此处duration现已赋了暗中同意值,所以这么些参数可传可不传。

满含扩充属性,能够一向 类名.属性名:类型

注意:Kotlin 的办法扩张实际不是真的修正了对应的类公事,而是在编写翻译器和
IDE 方面做了管理。使大家看起来疑似扩展了主意。

4. 函数式支持

  • Collections迭代

Kotlin使用lambda表明式来更便于地消除难点。浮现最棒的正是Collections的管理形式。

list.map(
  println(it) //it表示迭代的对象
)

查阅源码,大家得以看看实际map正是二个恢弘方法,给持有可以迭代的联谊提供该办法,map方法选用的参数是叁个lambda表明式,类型为T,再次回到值为RAV4类型(意味着放肆档次),那这里T类型实际上正是list的因素类型。

map方法源码.png

还能

list.map(::println)

::表示方法或类的援引。为啥能够直接传方法援用呢?

我们看看println方法源码,能够见见println选拔二个Any类也正是随便档期的顺序,並且再次来到值为空(Kotlin中空类型为Unit类,此处源码省略了回来值类型证明),所以完全符合map方法的要求。

println方法源码.png

注:相仿于景逸SUVxJava对数组的拍卖,Kotlin也提供了flatMap主意,具体能够本身打听。

  • 事件

在Java中,每一回我们去声多美滋个点击事件,都不能不去完成一个里面类,而在Kotlin中,能够一向表明大家要做什么样。

view.setOnClickListener { toast("Hello world!") }
//注:此处的toast方法是Kotlin默认已经提供的扩展方法

5. 互操作性

Kotlin调用Java和Java调用Kotlin与此前的Java
类之间调用方式未有太大差距,不详细介绍。

就举个Java调用Kotlin的小例子:

//Kotlin
class Overloads {
    fun overloaded(a: Int, b: Int = 0, c: Int = 1){
        println("$a, $b, $c")
    }
}

//Java
public class AccessToOverloads {
    public static void main(String... args) {
        Overloads overloads = new Overloads();
        overloads.overloaded(1, 2, 3);
    }
}

可以看来非常轻巧,这里要多介绍叁个Kotlin申明@JvmOverloads。如故定义了二个overloaded格局,加上评释后,Kotlin会自动重载成n个主意(n表示参数个数)

//Kotlin
class Overloads {
    @JvmOverloads
    fun overloaded(a: Int, b: Int = 0, c: Int = 1){
        println("$a, $b, $c")
    }
}

/**
在Java可以调用3个overloaded方法,分别是:
overloaded(a,b,c)
overloaded(a,b)
overloaded(a)
*/
public class AccessToOverloads {
    public static void main(String... args) {
        Overloads overloads = new Overloads();
        overloads.overloaded(1, 2, 3);
        overloads.overloaded(1);
        overloads.overloaded(1,3);
    }
}

6. 其他

  • 单例

第一说说单例的落到实处方式,在其后的实战中,将会时不常接触到object以此重要字。

先看Java,在Java中,完毕二个单例,大家供给:

  1. 封存贰个单例对象的静态实例

  2. 提供七个类措施让外部访谈独一的实例

  3. 构造方法选用private修饰符

而在Kotlin中,叁个修饰符就解除了。

object PlainOldSingleton {

}

怎么完毕的?我们看看反编写翻译的结果:

单例

能够看来写法和Java是全然同样的,又有多少个新主题材料,在类加载的时候就开头化了实例,这种艺术很糟糕,大家最佳接纳懒加载。那么在Kotlin中懒加载的2种完结格局如下:

class LazyNotThreadSafe {
      //方式一
    companion object{
        val instance by lazy(LazyThreadSafetyMode.NONE) {
            LazyNotThreadSafe()
        }

        //方式二,实际是Java的直译
    private var instance2: LazyNotThreadSafe? = null

        fun get() : LazyNotThreadSafe {
            if(instance2 == null){
                instance2 = LazyNotThreadSafe()
            }
            return instance2!!
        }
    }
}

一经想要实现线程安全,能够加上@Synchronized注明,那和Java中给类拉长Synchronized修饰符是相仿的。相像@Volatile讲明和Java的Volatile修饰符效率也是相像的。

抑或接受静态内部类的单例方法:

class LazyThreadSafeStaticInnerObject private constructor(){
    companion object{
        fun getInstance() = Holder.instance
    }

    private object Holder{
        val instance = LazyThreadSafeStaticInnerObject()
    }
}
  • 委托

Kotlin中,委托的实现依赖于爱抚字 by
by意味着将抽象主题的实例(by后面包车型地铁实例)保存在代理类实例的中间。

举例说下边那个事例中:BaseImpl类世袭于Base接口,并得以Base接口的富有的
public 方法委托给八个点名的对象。

interface Base {
    fun display()
}

class BaseImpl : Base {
    override fun display() {
        print("baseimpl display")
    }
}

class ProxyClass(base: Base) : Base by base

//程序入口
fun main(args: Array<String>) {
    var base = BaseImpl()
    var proxy = ProxyClass(base)
    proxy.display()
}
  • 泛型

在Java中,平时选拔Gson库来深入深入分析Json。调用方法的时候,大家需求传入想要转成的类的Class。大家都知晓Java的泛型实际上是伪泛型,对泛型帮助的最底层落成选拔的是项目擦除的办法(独有在编写翻译期才有)。

进而当使用Gson.fromJson(String json , Class<T> classOf)措施时,即使盛传了品种参数,当实际这一个T仍为个Object。

而在Kotlin中,能够应用reified,拜别Class。

reified的意味是具体化。作为Kotlin的叁个格局泛型关键字,它代表你能够在章程体内访问泛型钦点的JVM类对象。

inline fun <reified T: Any> Gson.fromJson(json: String): T{
//封装了`Gson.fromJson(String json , Class<T> classOf)`方法
    return fromJson(json, T::class.java)
}

此处供给钦定T类型为Any,即Object类。

接着能够没有必要传入Class,直接调用

fun main(args: Array<String>) {
    val json = "{state:0,result:'success',name:'test'}"
    var result : ReifiedBean =  Gson().fromJsonNew(json)
    println(result.name+","+result.result)
}

那要归功于inline,inline
意味着编译的时候确实要编写翻译到调用点。那么哪些方法调用了它,参数的连串都以鲜明的。也就无需传入Class了

** 7. 开脱不供给的凭仗**

Kotlin替换了成都百货上千第三方库,如ButterKnife、GoogleAutovalue、Ret伊丹爱莉mbda、Lombok和有个别昂CoraxJava代码。

而是也是能够百分百宽容安德拉xJava的,举个读取当守田本每一种字打字与印刷的例证。

Kotlin中使用RxJava

好了,闲话休说。

常备的获得View方法,要求叁个个去findViewById

习认为常的获取View方法

而使用Kotlin后

使用Kotlin获取View

大概有人注意到了,照旧须求findViewById啊!!骗子!说好的高雅呢?完全没觉着尤其简洁啊!!别急,Kotlin常用的收获控件情势不是如此的,容笔者介绍个Kotlin库——Anko。

12.1 使用 Gradle 构建 Kotlin工程

测试

我想在三种不乏先例的接收情形中运转标准:使用和不接纳Gradle
daemon+clean,未有公文改进的增量编写翻译,以致更改的文本的增量编译。
在更改从前,App Lock的Java代码有5,494个艺术和12,371行代码。
改写后,那个数字下落至4,987主意和8,564行Kotlin代码。
在重写时期未有爆发大的结构改良,因而在重写以前和之后测量试验编写翻译时间应当很好地领悟Java和Kotlin之间的营造时间的差异。

3. Kotlin库——Anko

简介
Anko是Kotlin官方开采的二个让开荒Android应用更迅捷更简便的Kotlin库

1. 再也不用findViewById

做过Android开拓的人都知道,结构文件写的多了,findViewById也是二个不小的工作量,并且还要先评释变量,在findViewById然后再强转成大家的控件,使用办法肖似如下

TextView username;
username=(TextView)findViewById(R.id.user);

username.setText("我是一个TextView");

有时写的是否想吐,也许有一些人说以后不是有点讲授的库,如butterknife,当我们选用注明时方可不用findViewById了,使用方法如下

@BindView(R.id.user)
TextView username;

username.setText("我是一个TextView");

实在是这么,使用申明后的确给大家少了有的专业量,不过那依旧未有最简单化,最简易的正是我们能够一贯给id为user的控件直接赋值,或者你会认为到那有一点难以置信。但是Kotlin确实不负义务了。大家得以一向那样写

user.text="我是一个TextView"

user正是大家布局文件宣称的id,.text就一定于setText(),在Kotlin语言中,大家看不到了像Java中的set/get方法了。

当大家想那样使用的时候(不用findViewById,直接利用xml控件id)
咱俩要求在gradle参预apply plugin: ‘kotlin-android-extensions’,必要加入上面一句代码

import kotlinx.android.synthetic.main.activity_login.*
注:activity_login正是我们的结构

import org.jetbrains.anko.toast
import org.jetbrains.anko.onClick

class Main2Activity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main2)
        my_textView.text = "kotline test"
        my_textView.textColor = Color.BLUE
        my_button.text = "Click"
        my_button.onClick { toast("aa") }
    }
}  

为什么Anko不需要.setText能够间接.text呢?其实那是经过扩大函数落成的,大家看下内部的落实细节:

public var TextView.text: CharSequence        
  get() = getText()           
  set(v) = setText(v)

2. Anko Layout

平日大家使用xml文件写我们的布局,不过存在有一点点劣点:如不是体系安全,不是空安全,拆解解析xml文件消耗越多的CPU和电量等等。

而Anko
Layout能够利用DSL动态创立我们的UI,并且它比大家采纳Java动态成立构造方便广大。首如果更轻便,它有着近乎xml创设构造的层级关系,能让大家更易于阅读。

 verticalLayout {
            val textView = textView("textview")
            val name = editText()
            val button=button()
                    button.onClick {
                toast("${name.text}")
            }
        }

咱俩在OnCreate方法中能够去掉setContentView,然后参与地点代码就能够展现如下图的意义,即二个垂直的线性结构中,放了二个TextView,二个EditText,和叁个Button。何况Button中有叁个点击事件,当点击时将EditText的剧情以toast呈现。

Anko Layout.png

在下边创造UI进程中,大家直接把创造UI的代码写在onCreate方法中了,当然,还大概有一种写法。大家创制八个里头类进行AnkoComponent接口,同等看待写createView方法,该措施重回一个View,相当于大家创立的布局。改正如下

inner class UI : AnkoComponent<LoginActivity> {
        override fun createView(ui: AnkoContext<LoginActivity>): View {
           return with(ui){
               verticalLayout {
                   val textView=textView("我是一个TextView"){
                       textSize = sp(17).toFloat()//自定义字体大小
                       textColor=context.resources.getColor(R.color.red)//自定义颜色
                   }.lparams{
                       margin=dip(10)//它表示将10dp转换为像素
                       height= dip(40)
                       width= matchParent
                   }
                   val name = editText("EditText")
                   button("Button") {
                        onClick { view ->
                            toast("Hello, ${name.text}!")
                        }
                   }
               }
           }
        }
    }

接下来在onCreate方法中加一句代码,就能够创制我们的布局页面了。如下

UI().setContentView(this@LoginActivity)

其中,dip(10),表示将10dp转变为像素的情趣,是Anko的扩张函数,提起扩展函数,小编发觉Kotlin源码里多量地接纳扩张函数,那也是Kotlin语言的优势之一。确实很有力,比方dip扩张(采撷View扩充)

inline fun View.dip(value: Int): Int = context.dip(value)
fun Context.dip(value: Int): Int = (value * resources.displayMetrics.density).toInt()

好似笔者辈早先说的toast、text也是进行函数近似

inline fun AnkoContext<*>.toast(message: CharSequence) = ctx.toast(message)
fun Context.toast(message: CharSequence) = Toast.makeText(this, message, Toast.LENGTH_SHORT).show()

只是为了分界面和逻辑分离,分界面依然提议选取xml,所以这里就窘迫Anko
Layout多做牵线了。

3. 此外地方

比如互连网央求AsyncTask

 doAsync {
            //后台执行代码

            uiThread { 
            //UI线程
            toast("线程${Thread.currentThread().name}")

         }
      }

其余剧情可以直接访谈Anko

12.1.1 kotlin-gradle 插件

为了用 Gradle 营造 Kotlin工程,大家必要设置好 kotlin-gradle 插件:

buildscript {
    ext {
        kotlinVersion = '1.1.3-2'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
                ...
    }
}

apply plugin: 'kotlin'

还要增多 kotlin-stdlib 依赖:

dependencies {
    compile("org.jetbrains.kotlin:kotlin-stdlib-jre8:${kotlinVersion}")
    compile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
}

本来,那么些操作在我们新建项目标时候,平日大家只须求选取相应的选项,
AMDliJ IDEA 就能够一直帮大家达成了基本的配备了。

大家应用 kotlin-gradle-plugin 编写翻译 Kotlin 源代码和模块。使用的 Kotlin
版本平常定义为 kotlinVersion 属性。

针对 JVM,我们须求运用 Kotlin 插件:

apply plugin: "kotlin"

clean + 不用Gradle daemon Build

那是三种语言中创设时间最差的动静:从冷运转运转三个clean的营造。
对于那一个测验,作者禁止使用了Gradle daemon。
此处是13个营造所花费的光阴:

澳门葡萄京官方网站 1

在此种景观下的结果是,Java构建时间平均为15.5秒,而Kotlin平均为18.5秒:扩展了17%。
那对Kotlin来讲并非贰个好的以前,可是多数人不会如此编写翻译他们的代码。

对于未有Gradle daemon 而且clean营造,Java编写翻译比Kotlin快17%

Kotlin的缺点

即便 Kotlin 十分棒,可是它并不到家。作者列举了有些自己反感的片段。

12.1.2 Kotlin 与 Java 混合编制程序

Kotlin 源代码能够与同三个文件夹或分歧文件夹中的 Java
源代码混用。私下认可约定是行使差异的文件夹:

sourceSets {
    main.kotlin.srcDirs += 'src/main/kotlin'
    main.java.srcDirs += 'src/main/java'
}

一旦选择私下认可的目录,下边包车型地铁布署能够节省不写。

假设不选用私下认可约定,那么应该更新相应的 sourceSets 属性

sourceSets {
    main.kotlin.srcDirs += 'src/main/myKotlin'
    main.java.srcDirs += 'src/main/myJava'
}

clean +Gradle daemon Build

以此JIT编写翻译器的问题,就疑似JVM中,是它们必要时间来编写翻译对报告的实施的代码,等等的处理随即间扩大的属性,因为它运维。
如若悬停JVM进度,那么品质增益会吐弃。
在营造Java代码时,经常在每趟营造时运营和休息JVM。
那反逼JVM每便创设时重做专门的职业。
为了消除这一个标题,Gradle附带了三个护理进度,它将要营造之间保持活跃,以便保险JIT编写翻译的性质进步。
你能够透过在gradle命令行加参数–daemon或然在gradle.properties文件增加一句org.gradle.daemon=true。

澳门葡萄京官方网站 2

能够看看,第一遍运营所成本的小时与未有daemon的小时相近,但继续运营的天性升高,直到第八回运转。
在此种情形下,查看第一遍运维后的平均营造时间更有用,在这之中daemon已职业过了。
对于热运转,在Java中推行clean构建的平均时间为14.1秒,而Kotlin以16.5秒的进度运维时刻:多了13%。

对于clean + Gralde daemon 编译,Java编译比Kotlin快13%。

Kotlin正在高出Java,但依然某个失利。 不过,无论接受什么语言,Gradle
daemon都会将塑造时间压缩40%上述。 固然您还向来不使用它,你应该用上。

之所以Kotlin编写翻译在一体化代码情形下比Java慢一点。
可是你平凡只会对多少个文本进行改良后编译,增量创设将有例外的性质。
所以,让大家来会见Kotlin在增量编写翻译是不是足以境遇。

1. 未有命名空间

Kotlin 允许你在文书中定义一流的函数和总体性,可是那会拉动麻烦——全数从
Kotlin
引用的一等声明无法区分。那让我们一时候在读代码时很难神速分明用的是哪四个函数。

比方,你定义那样叁个世界级函数:

fun foo() {...}

您能够由此 foo(卡塔尔 调用。

假如你在差异的包里面也设有近似的主意,在调用时就不能够掌握有别于出是调用的哪位方法。你能够因此在后面增加包名的措施去调用,但是一旦
Java 约定的包名很深,如同不太融洽。

一种恍若的缓和方案是使用单例的 object 类。

object FooActions { fun foo() {...}}

如此您在 Kotlin 中得以经过 FooActions.foo(卡塔尔国 调用,可是在 Java
中你必定要如此 FooActions.INSTANCE.foo()这么调用,那看起来很麻烦。

你也得以运用 @JvmStatic 去评释该办法,进而省去INSTANCE

其实远非命名空间实际不是如何大不断的事,但是倘若 Kotlin
能够提供的话,能省不菲事。

12.1.3 配置 Gradle JavaScript 项目

当针对 JavaScript 时,须动用不一致的插件:

apply plugin: "kotlin2js"

除开输出的 JavaScript 文件,该插件私下认可会创立八个带二进制描述符的额外 JS
文件。

万一是营造其余 Kotlin
模块能够依靠的可重用库,那么该公文是必备的,並且与转移结果同盟分发。

二进制描述符文件的生成由 kotlinOptions.metaInfo 选项决定:

compileKotlin2Js {
    kotlinOptions.metaInfo = true
}

提示:示例工程得以参照
https://github.com/EasyKotlin/chapter2_hello_world_kotlin2js

增量营造

编写翻译器最根本的性子特点之一是接受增量编写翻译。
正常创设将另行编写翻译项目中的全体源文件,可是增量创设将跟踪自上次构建以来哪些文件已更动,并且只重复编写翻译那么些文件和正视它们的文本。
那只怕对编写翻译时间有高大的熏陶,特别是对于大型项目。
增量营造在kotlin1.0.2之后版本扶助,你能够在你的gradle.properties文件增多kotlin.incremental = true达成。
那么当使用增量编写翻译时,Kotlin与Java的编写翻译时相譬如何?
以下是未有变动文件时利用增量编译的基准:

澳门葡萄京官方网站 3

接下去,我们将动用改正后的源文件测量检验增量编写翻译。
为了测试那一个,笔者在历次营造从前改动了几个java文件,Kotlin也相近。
在此个标准测量检验中,源文件是未曾其余文件信赖的UI文件:澳门葡萄京官方网站 4

末段,让大家看看使用更正的源文件实行增量编译,其汉语件导入到项目中的好些个任何文件

澳门葡萄京官方网站 5

你能够看到Gradle
daemon仍须求两一回运维来预热,但是随后二种语言的性质是特别相符的。
未有变动,Java每种热建设构造4.6秒,而Kotlin平均4.5秒。
当我们改善两个不曾被其余此外文件使用的公文时,Java平均供给7.0秒来做二个热塑造,Kotlin是6.1秒。
最终,当我们改动项目中众多别样文件导入的公文时,Java必要7.1秒本事在Gradle
daemon加热后实施增量创设,而Kotlin平均6.0秒。

在最广大的场馆下 – 启用增量编写翻译的一对创设 –
Kotlin编写翻译速度快或略快于Java。

2. 尚无静态修饰符

Kotlin为静态函数和天性提供了一个和 Java
不平等的管理方式。并不是说有多烂,只是感到让代码变得不干净而且还未须要。

举个例子说,在 Android 的 View 类中定义的静态属性 View.VISIBLE 和静态函数
View.inflate

public class View { 
  public static final int VISIBLE = 0x00000000; 
  public static final int INVISIBLE = 0x00000004;
  public static View inflate(Context context, int resource) {...}
}

以此概念是归纳的。然则,在 Kotlin 代码中:

class View { 
  companion object { 
    @JvmField 
    val VISIBLE: Int = 0x00000000 
    @JvmField 
    val INVISIBLE: Int = 0x00000004 
    @JvmStatic 
    fun inflate(context: Context, resource: Int) {...} 
  }
}

注:companion object为伴生对象

即使 Kotlin
的版本并不曾那么恐怖,不过它的复杂程度当先了小编对这门语言的预料。倘诺去掉表明,你在
Java 中就只可以选取那样骇人传说的语法去调用:

// With annotations:
View.VISIBLE;
//Without annotations:
View.Companion.getVISIBLE();

12.1.4 配置 Gradle Android项目

Android 的 Gradle 模型与日常 Gradle 有一些差异,所以一旦大家要创设贰个用
Kotlin 编写的 Android 项目,大家须要用 kotlin-android 插件替代
kotlin 插件:

buildscript {
    ext.kotlin_version = '1.1.2-4'
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

万般大家利用 Android Studio,都以生成贰个带 app
子项目的工程。多品种配置的完结普通是在三个根项目路径下将具备类型作为子文件夹包涵进去。比如大家在档案的次序根路线上边包车型大巴settings.gradle中如下配置:

include ':app'

每多个子项目都怀有本人的build.gradle文件来声称本人哪些营造。

诸如,大家在子项目app的营造配置文件 build.gradle 中二个一体化的安插如下:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "com.kotlin.easy.kotlinandroid"
        minSdkVersion 14
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
}
repositories {
    mavenCentral()
}

其中,

apply plugin: ‘kotlin-android’ 是 Kotlin Android 插件。
compile “org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version” 是
Kotlin 运维标准库。

其余, Android Studio 暗中认可加载源码的目录是 src/main/java,假设想钦命Kotlin 代码在src/main/kotln目录,能够在 android 下加多以下内容:

android {
  ……
  sourceSets {
    main.java.srcDirs += 'src/main/kotlin'
  }
}

晋升: 关于 Kotlin Android 的 Gradle 完整配置实例可仿效
https://github.com/EasyKotlin/KotlinAndroid

结论

大家对多少个分化的风貌进行了标准测验,看看Kotlin在编写翻译时间是否能够跟上Java。
纵然Java在clean构建比Kotlin 快10-15%,但那一个景况少之又少。
对于超多开采职员来讲,更普及的境况是一些创设,当中增量编写翻译进行了多量改革。
随着Gradle daemon运营和增量编写翻译的开启,Kotlin编译速度快或略快于Java。
那是贰个作者一心未有想到并且令人影像深远的结果。
小编不得不赞美Kotlin团队企划一种不只有有着非常多出色功能,并且能够快捷编写翻译的语言。
即便您因为编写翻译时筹算利用Kotlin,你不用怀恋:Kotlin的编译速度和Java相仿快。

克罗地亚语原版的书文:Kotlin vs Java Compilation
Speed

编译:掘金

(文/开源中中原人民共和国State of Qatar    

3. 编写翻译方法数量

Kotlin
断定会回退项目中的代码行数,然而它也会增进代码在编写翻译未来的办法数。主要缘由便是Kotlin 属性的完毕方式。

和 Java 不相像,Kotlin 未有提供单身定义域的艺术。你必得使用 val 也许 var
来声称变量。那样有三个好处,就是节约了像 Java 同样定义 getters 和
setters 方法。

而是那亟需明确的本钱。每二个public的 val
变量都会变卦多少个「扶持域」和一个能被 Java 调用的 getter
方法。每叁个public的 var 变量都会转移 getter 和 setter 方法。

// kt 文件:
// 默认就是public,无需额外添加public修饰符
val strValPublic: String = "strValPublic"
var strVarPublic: String = "strVarPublic"

// 以下是反编译结果:
public final class VarAndValKt {
   @NotNull
   private static final String strValPublic = "strValPublic";
   @NotNull
   private static String strVarPublic = "strVarPublic";

   @NotNull
   public static final String getStrValPublic() {
      return strValPublic;
   }

   @NotNull
   public static final String getStrVarPublic() {
      return strVarPublic;
   }

   public static final void setStrVarPublic(@NotNull String var0) {
      Intrinsics.checkParameterIsNotNull(var0, "<set-?>");
      strVarPublic = var0;
   }
}

展开:Intrinsics.checkParameterIsNotNull 方法其实非常粗大略,原理:

public static void checkParameterIsNotNull(Object value, String paramName) {
    if (value == null) {
        throwParameterIsNullException(paramName);
    }
}

实在全体空安全的秘闻都在此个类里面了

人心大快的是,私有属性的 getters 和 setters 会生成域并非生成方法。

// kt文件:
private val strValPrivate: String = "strValPrivate"
private var strVarPrivate: String = "strVarPrivate"

// 以下是反编译结果:
public final class VarAndValKt {
   private static final String strValPrivate = "strValPrivate";
   private static String strVarPrivate = "strVarPrivate";
}

由此只要您把项目中Java代码转成Kotlin,而且事情发生此前的 Java
代码中定义了多量的公开域(那在概念常量的时候很普及),你会好奇的意识最后编写翻译生成的章程数量大幅度上涨。

一经您的 Android 应用快周围方法数节制了,作者提议你为无需自定义 getter
方法的常量加上 @JvmField 评释。那样会阻拦 getters
方法的生成,进而减弱你的主意数。

// kt 文件:
@JvmField
val strValPublic: String = "strValPublic"
@JvmField
var strVarPublic: String = "strVarPublic"

// 以下是反编译结果:
// 注意看,get set方法消失,取而代之的是private修饰符变成了public
public final class VarAndValKt {
   @JvmField
   @NotNull
   public static final String strValPublic = "strValPublic";
   @JvmField
   @NotNull
   public static String strVarPublic = "strVarPublic";
}

12.1.5 配置Kotlin 标准库依赖

除开上边的 kotlin-gradle-plugin 注重之外,我们还亟需增添 Kotlin
标准库的信赖:

repositories {
    mavenCentral()
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib"
}

万一针对 JavaScript,使用
compile "org.jetbrains.kotlin:kotlin-stdlib-js" 替代之。

只假使针对性 JDK 7 或 JDK 8,那么可以使用扩大版本的 Kotlin
标准库,当中蕴藏为新版 JDK 增添的额外的扩展函数。使用以下注重之一来代替
kotlin-stdlib

compile "org.jetbrains.kotlin:kotlin-stdlib-jre7"
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8"

假使项目中动用 Kotlin 反射,增添反射信任:

compile "org.jetbrains.kotlin:kotlin-reflect"

借使项目中利用测量试验框架,大家抬高相应的测量检验库重视:

testCompile "org.jetbrains.kotlin:kotlin-test"
testCompile "org.jetbrains.kotlin:kotlin-test-junit"
4. 没有CE机制

Kotlin官网对CE的解释:

CE

翻译一下:
Kotlin
未有受检的极度。那当中有无数缘故,但大家会提供二个简约的例证。
以下是 JDK 中 StringBuilder 类达成的二个演示接口
Appendable append(CharSequence csq) throws IOException;
其一具名是如何意思? 它是说,每一次自个儿扩展一个字符串到一些事物(叁个StringBuilder、某种日志、三个调节台等)上时作者就不得不捕获那贰个IOException。 为啥?因为它或者正在实施 IO 操作(Writer 也促成了
Appendable)…… 所以它招致这种代码到处可以看到的面世

咱俩见到Java的CE机制被问责了相当久,不过只要你通过理性的剖释,就能意识,Java
的有一点设计看起来“繁复多余”,实际上却是经过深思远虑的主宰。Java
的设计者知道有个别地方能够差非常少,却有意把它做成多余的。大家不可能盲目地以为简短正是好,多写多少个字正是丑陋不文雅,其实不是那么的。

Kotlin有特别机制,但不需要您在函数的品种里面评释也许现身的特别类型,也不行使静态类型系统对极度的管理进展自己争辩和注明。那当本身每调用三个函数(不管是正式库函数,第三方库函数,依旧队友写的函数,以致自个儿要好写的函数),作者都会纳闷这一个函数是或不是会抛出特别。由于函数类型上不要求标志它大概抛出的老大,为了保证三个函数不会抛出十分,你就须要检查这么些函数的源代码,以至它调用的那几个函数的源代码,以致整个调用树!

在这里种疑虑的事态下,你就只可以做最坏的策画,你就得把代码写成:

try
{
    foo()
} 
catch (e:Exception)
{
    printf(e)
}

因为不晓得 foo 函数里面会有何极其现身,所以您的 catch
语句里面也不清楚该做怎么样。超越八分之四人只可以在内部放一条
log,记录非常的发出。那是一种特不好的写法,不但繁复,何况大概覆盖运维时不当。

那么 Java 呢?因为 Java 有
CE,所以当您看看一个函数未有注脚相当,就能够放心的省掉
try-catch。所以那个标题,顺其自然就被防止了,你没有必要在众多地点疑忌是不是必要写
try-catch。Java 编写翻译器的静态类型检查会告知您,在怎么地点必得写
try-catch,大概加上 throws 评释。

12.1.6 增量编写翻译

Kotlin 援救 Gradle
中可选的增量编写翻译。增量编写翻译追踪创设之间源文件的校正,因而唯有受那些改换影响的文件才会被编写翻译。从
Kotlin 1.1.1 起,暗中同意启用增量编译。

结尾

在就学进度中,笔者意识,若是具有扎实的Java根基,这东西精晓起来是全速的,所以毕竟学不学Kotlin,其实是不要焦急的。二个新的言语想要火速的推广,那么大概独有在运转作效果能上富有升级,才是最大的优势,而Kotlin并不有所那样的性质。

小编们能够看下Java和Kotlin的编写翻译速度相比。

12.1.7 编写翻译器选项

要钦定附加的编写翻译选项,能够使用 Kotlin 编写翻译任务compileKotlin的
kotlinOptions 属性。

布局单个职分示例:

compileKotlin {
    kotlinOptions {
        suppressWarnings = true
    }
}
编写翻译速度相比较

自个儿不会策动比较一行代码的编写翻译速度;相反,相比的是将代码从Java调换为Kotlin是或不是会影响其全体创设的时刻。

在改造此前,App Lock的Java代码有5,4九十三个主意和12,371行代码。
改写后,那些数字下落低到4,987方法和8,564行Kotlin代码。
在重写时期从不爆发大的构造修改,因而在重写在此以前和未来测验编写翻译时间应当很好地明白Java和Kotlin之间的营造时间的差异。小编写了二个shell来重新推行gradle。全部测量检验三番两次举行11回。

  • clean + 不用Gradle daemon Build
    那是三种语言中创设时间最差的景观:从冷运转运维四个clean的创设。
    对于那一个测验,作者禁止使用了Gradle daemon。
    那边是12个营造所花费的时光:

Paste_Image.png

对此还未Gradle daemon
何况clean创设,Java编译比Kotlin快17%,不过当先五中年人不会那样编写翻译他们的代码。

  • clean +Gradle daemon Build

Paste_Image.png

能够看来,Kotlin第一遍运转所开支的日子与上三个方案的光阴一模二样,但继续运转的属性稳步提升。

对于clean + Gralde daemon 编译,Java编译比Kotlin快13%。

为此Kotlin编写翻译在全体代码意况下比Java慢一点。
不过您平时只会对多少个文本实行转移后编写翻译,所以,大家来看看Kotlin在增量编写翻译是还是不是能够遇到Java。

  • 增量编写翻译

尚未更改文件时利用增量编写翻译

转移未有此外文件正视的UI文件的增量编写翻译

更改的源文件的增量编写翻译

进而尽管Java在clean创设比Kotlin 快10-15%,但那一个情形少之又少。
对于好些个开辟职员来讲,更广大的气象是一些塑造,随着Gradle
daemon运营和增量编写翻译的拉开,Kotlin编译速度快或略快于Java。

故而,照旧那句话,几个新的言语想要火速的推广,在运作成效上全体升高,才是最大的优势,Kotlin鲜明值得学习的,但并不曾传的那么浮夸。有生机就去读书,有投机的学习布署也能够放一放,延后再学。

自己想只有用得多了,Kotlin的优势才会慢慢显现出来,那须要多个相比长久的过渡期。

转发请注脚原著出处:http://www.jianshu.com/p/f364e3f9cc36
有荒唐请多多指正!

12.2 使用 Kotlin 编写营造和安顿文件

多个依照 Kotlin 来写 Gradle 营造脚本及插件的措施只怕会是如何的?
它对团队的赞助什么——特别是大型集体——加快职业速度并编写结构更加好、更便于维护的构建脚本?

这一个或许性非常使人陶醉。

因为 Kotlin 是一种静态类型语言,在 IDEA 和 Eclipse
中都有尖锐的支撑,所以能够从自动补全到重构,以至当中的全部都能为 Gradle
顾客提供适宜的 IDE 支持。 何况由于 Kotlin
具备充裕的效率,如一等函数和增添方法,因而它能够保存和修正 Gradle
营造脚本的精品部分——包含简明的证明式语法以至轻易营造 DSL 的技能。

Gradle 团队认真地观测了这个恐怕性,与 Kotlin 团队紧凑合营,为 Gradle
开辟一种新的基于 Kotlin 的营造语言——我们称为 Gradle Script Kotlin。

下边大家就来归纳介绍一下采纳 Kotlin 脚本来编写 Gradle 的布置文件。

大家就上述一章中的 chapter11_kotlin_springboot 工程为例。

第一我们在根目录下新建三个settings.gradle 配置文件:

rootProject.name = 'chapter11_kotlin_springboot'
rootProject.buildFileName = 'build.gradle.kts'

钦命 gradle 创设文件名是 ‘build.gradle.kts’ 。
下一场,大家新建 ‘build.gradle.kts’ , 完整的剧情如下:

buildscript {
    val kotlinVersion = "1.1.3-2"
    val springBootVersion = "2.0.0.M2"
    extra["kotlinVersion"] = kotlinVersion

    repositories {
        mavenCentral()
        maven { setUrl("https://repo.spring.io/snapshot") }
        maven { setUrl("https://repo.spring.io/milestone") }
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
        classpath("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion")
    }
}

apply {
    plugin("kotlin")
    plugin("kotlin-spring")
    plugin("eclipse")
    plugin("org.springframework.boot")
    plugin("io.spring.dependency-management")
}

version = "0.0.1-SNAPSHOT"

configure<JavaPluginConvention> {
    setSourceCompatibility(1.8)
    setTargetCompatibility(1.8)
}


repositories {
    mavenCentral()
    maven { setUrl("https://repo.spring.io/snapshot") }
    maven { setUrl("https://repo.spring.io/milestone") }
}

val kotlinVersion = extra["kotlinVersion"] as String

dependencies {
    compile("org.springframework.boot:spring-boot-starter-actuator")
    compile("org.springframework.boot:spring-boot-starter-data-jpa")
    compile("org.springframework.boot:spring-boot-starter-freemarker")
    compile("org.springframework.boot:spring-boot-starter-web")
    compile("org.jetbrains.kotlin:kotlin-stdlib-jre8:${kotlinVersion}")
    compile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
    runtime("org.springframework.boot:spring-boot-devtools")
    runtime("mysql:mysql-connector-java")
    testCompile("org.springframework.boot:spring-boot-starter-test")
}

提醒: 依据上述手续,新建完文件build.gradle.kts后,IDEA 或然识别不了那一个DSL 函数,那个时候我们重启一下 IDEA 就可以(那是二个 bug,前面会修复)。

这当中的 Gradle DSL 的相关函数与类都在 Gradle 软件包的 lib 目录下:
lib/gradle-script-kotlin-(版本号卡塔尔.jar 。大家大约用下边包车型大巴报表表达:

函数(类) 对应的gradle-script-kotlin代码
buildscript open fun buildscript(@Suppress("unused_parameter") block: ScriptHandlerScope.() -> Unit) = Unit
repositories fun ScriptHandler.repositories(configuration: RepositoryHandler.() -> Unit) =repositories.configuration()
buildscript.dependencies DependencyHandlerScope(scriptHandler.dependencies)
configure inline fun <reified T : Any> Project.configure(noinline configuration: T.() -> Unit)
Project.dependencies DependencyHandlerScope(dependencies).configuration()

也便是说,其实那个配置函数背后都以由 Gradle 的 DSL 来兑现的。

骨子里,那些配置语法看起跟 Groovy 的很像。举个例子:

Groovy :

    repositories {
        mavenCentral()
        maven { url "https://repo.spring.io/snapshot" }
        maven { url "https://repo.spring.io/milestone" }
    }

Kotlin:

repositories {
    mavenCentral()
    maven { setUrl("https://repo.spring.io/snapshot") }
    maven { setUrl("https://repo.spring.io/milestone") }
}

再例如:
Groovy:

sourceCompatibility = 1.8
targetCompatibility = 1.8

Kotlin:

configure<JavaPluginConvention> {
    setSourceCompatibility(1.8)
    setTargetCompatibility(1.8)
}

提示: 本节示范工程源码
https://github.com/EasyKotlin/chapter11_kotlin_springboot/tree/build.gradle.kts

本章小结

本章我们差不离介绍了采取 Kotlin 集成 Gradle
开采进度中的一些常用的配置格局。Gradle
是三个格外好用的营造筑工程具,当大家的 Kotlin 工程的布置文件也是 Kotlin
代码的时候,我们的专业又尤为单纯了大多,只需求在意 Kotlin 就可以。

在下一章中,大家将学习使用 Kotlin 和 Anko 来进行Android开荒的相关内容。