enter image description here

原文链接在我的博客: 初见Kotlin

前段日子Kotlin发布了1.0版,号称Android界的Swift,一副拯救苦逼Android码农于水火中的架势。那么它有何神奇之处呢?经过一段时间的摸索,Kotlin在我眼中定位为“通吃型”语言,服务端不是问题,还能生成JavaScript,另外又有针对Android开发的增强服务特性。

enter image description here

Kotlin一出世就被拿来跟Scala比较,恰巧Scala也是我喜欢的一门JVM语言。其实,我个人感觉Kotlin并非Scala的小弟,只是说有了valvar的表象,给许多开发者这种感觉,但要这么说的话,Scala的函数/方法定义用def而Kotlin却用fun这又怎么说呢?此外,Kotlin的伴生对象跟Scala中的概念也区别不小。另一种说法是Kotlin比Scala简单,也许Kotlin尚未实现Scala中我喜欢的yield功能,但要从发展角度来看,Kotlin出道时间短,后续要添加的功能应该会层出不穷。Kotlin的用法并不简单要说“骨子里”的像,我宁愿觉得Kotlin更像Java

  • 号称“100% interoperable with Java™”:使用一段时间的感受是,写着写着,就有可能不知不觉中无缝地使用Java代码风格,写完了才恍然大悟......
  • 一方面Kotlin添加了大量函数式风格,它的map、filter等等操作比Java 8 Stream的来得简洁直接。但隐约感受得到,这只是Kotlin特性中表面且很小的一部分,涉及过多的功能需求时,还是要寻求Java的特性支持。这点不像Scala,Scala是能不用Java原生特性就不用,而Kotlin则是需要用时你用就是了。不知道这是好事还是坏事,但终究看个人偏好吧,对于Java底子较好或较适应Java风格的开发者来说,这则是一个不错的起点。

上面是我觉得有必要澄清的一些概念。而以下则是Kotlin吸引我研究下去的一些因素

  • Null Safety:别小看这一点,强迫症真能防范大量潜在问题。
  • Extension Functions:很喜欢这个特性,即开即用的感觉。
  • JetBrains家的东西,还是有些功底的,更重要的是跟闻名遐迩的自家开发工具必然结合紧密。
  • 充分考虑Android平台开发的环境及特性适配,也难怪称为“Android开发的Swift”。
  • 与Java的互操作性:也许会让大票开发者不感冒,但对我来说再好不过。

以下是Kotlin的一些限制,当然也只是我个人的一些看法:

  • 稳定性:尚待提高,特别是REPL工具,动不动就导致退出REPL环境。此外,代码中的空行及注释都会在REPL中引发异常。
  • 文档:官方文档比较初级,且资源不多。
  • 普及率:小众。TIOBE从上月起已经纳入了Kotlin的观察,首月排名貌似158位。

整个感受,用这个示例实现来解释最恰当不过了:

给一个自定义日期类添加ComparisonRangeFor迭代功能。

data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) : Comparable<MyDate> {
    override fun compareTo(other: MyDate): Int {
        val calendar1: java.util.Calendar = java.util.Calendar.getInstance()
        val calendar2: java.util.Calendar = java.util.Calendar.getInstance()
        calendar1.set(this.year, this.month - 1, this.dayOfMonth)
        calendar2.set(other.year, other.month - 1, other.dayOfMonth)

        return if (calendar1.before(calendar2)) -1 else if (calendar1.after(calendar2)) 1 else 0
    }
}

class DateRange(val start: MyDate, val end: MyDate): Iterable<MyDate> {
    private var _dateRange: MutableList<MyDate> = mutableListOf<MyDate>()

    init {
        val calendar1: java.util.Calendar = java.util.Calendar.getInstance()
        val calendar2: java.util.Calendar = java.util.Calendar.getInstance()
        calendar1.set(start.year, start.month - 1, start.dayOfMonth)
        calendar2.set(end.year, end.month - 1, end.dayOfMonth)

        if (start < end) {
            _dateRange.add(MyDate(calendar1.get(java.util.Calendar.YEAR),
                                  calendar1.get(java.util.Calendar.MONTH) + 1,
                                  calendar1.get(java.util.Calendar.DAY_OF_MONTH)))

            val days = (calendar2.getTimeInMillis() - calendar1.getTimeInMillis()) / 1000 / 60 /60 /24
            for (day in 1..days) {
                calendar1.add(java.util.Calendar.DAY_OF_MONTH, 1)
                _dateRange.add(MyDate(calendar1.get(java.util.Calendar.YEAR),
                                      calendar1.get(java.util.Calendar.MONTH) + 1,
                                      calendar1.get(java.util.Calendar.DAY_OF_MONTH)))
            }
        }
    }

    override operator fun iterator(): Iterator<MyDate> {
        return MyDateIterator()
    }

    inner class MyDateIterator: Iterator<MyDate> {
        private var _index: Int = 0

        override operator fun hasNext(): Boolean {
            return _index != _dateRange.size
        }

        override operator fun next(): MyDate {
            return _dateRange[_index++];
        }
    }
}

operator fun MyDate.rangeTo(other: MyDate): DateRange {
    return DateRange(this, other)
}

测试代码:

>>> fun iterateOverDateRange(firstDate: MyDate, secondDate: MyDate, handler: (MyDate) -> Unit) {
...     for (date in firstDate..secondDate) {
...         handler(date)
...     }
... }
>>> iterateOverDateRange(MyDate(2016, 3, 10), MyDate(2016, 3, 14)) { println(it) }
MyDate(year=2016, month=3, dayOfMonth=10)
MyDate(year=2016, month=3, dayOfMonth=11)
MyDate(year=2016, month=3, dayOfMonth=12)
MyDate(year=2016, month=3, dayOfMonth=13)
MyDate(year=2016, month=3, dayOfMonth=14)
>>> iterateOverDateRange(MyDate(2016, 5, 1), MyDate(2016, 5, 5)) { println(it) }
MyDate(year=2016, month=5, dayOfMonth=1)
MyDate(year=2016, month=5, dayOfMonth=2)
MyDate(year=2016, month=5, dayOfMonth=3)
MyDate(year=2016, month=5, dayOfMonth=4)
MyDate(year=2016, month=5, dayOfMonth=5)
>>> iterateOverDateRange(MyDate(2016, 5, 1), MyDate(2016, 5, 1)) { println(it) }
>>> (MyDate(2016, 3, 10)..MyDate(2016, 3, 14)).map { println("${it.year}-${it.month}-${it.dayOfMonth}") }
2016-3-10
2016-3-11
2016-3-12
2016-3-13
2016-3-14
[kotlin.Unit, kotlin.Unit, kotlin.Unit, kotlin.Unit, kotlin.Unit]
>>>
>>> fun checkInRange(date: MyDate, first: MyDate, last: MyDate): Boolean {
...     return date in first..last
... }
>>> checkInRange(MyDate(2016, 3, 13), MyDate(2016, 3, 10), MyDate(2016, 3, 14))
true
>>> checkInRange(MyDate(2016, 3, 8), MyDate(2016, 3, 10), MyDate(2016, 3, 14))
false
>>> checkInRange(MyDate(2015, 3, 13), MyDate(2016, 3, 10), MyDate(2016, 3, 14))
false
>>>

结论:

刚好现在看到一个开发者的困惑:“Kotlin让我感到不安。它离开Java 能玩得起吗 ?”我觉得Kotlin发展的前提是不离开Java,这个前提没了,估计Scala、Clojure一样没戏——Kotlin本身就是Java形态的增强与补充!

该不该学习Kotlin?——Kotlin就是一门语言,不是什么“十全大补丸”,但其现在面临的最急迫任务就是普及与推广,至少要达到Groovy、Scala或Clojure等“同门师兄弟”的地位,虽然这些个JVM语言的排名也不是很高。“该不该学”这个问题真没有答案。总之,它就是一门新兴的语言而已。

enter image description here