Why use Kotlin & Kotlin Use Case

最先进的语言Kotlin

Posted by Mio4kon on 2016-08-30

为什么选择Kotlin而不是Scala

Scala开源客户端:
shadowsocks-android

Kotlin 与 Scala 的方法大相径庭,那为什么选择Kotlin而不是Scala?

  • 没有太多的学习曲线,现学现用.
  • Java紧密结合.
  • 相对于Scala库小很多(小于7000个方法数)
  • JetBrains家的东西,IDE完美支持.

Kotlin相对于Java的优势

case 1 - null问题

java经常会遇到空指针的问题,于是经常会遇到一个问题:这个对象会不会为空?
这会导致:Android代码往往充斥着不必要的null检查和空指针的崩溃

Kotlin规定声明变量默认必须要初始化.

编译器会报错:

var str : String =null   

如果的确开始没有初始值需要这么定义:

var str : String ?=null

在使用的时候:

1
2
3
4
5
6
7
8
9
10
11
//确保str不可能为空
str!!.length
//安全执行
str?.length
//或者自己家加判断
if(str!=null){
str.length
}
//甚至可以在为空的时候设置默认值
val len = str?.length ?: -1 //-1

case 2 - 扩展函数

试想一下如果想拿到一个String的最后一个字符该怎么做?

先不去考虑空字符串的情况下,用java:

1
2
3
4
5
6
7
class StringUtils {
public static char last(String s) {
return s.charAt (s.length () - 1);
}
}
StringUtils.last ("HaHa!");//!

如果用Kotlin的话,一切都可以回归于对象!

1
2
3
4
5
fun String.last(): Char {
return this[length - 1]
}
"HaHa!".last() //!

case 3 - Data Classes

一句话就可以搞定JavaBean

data class Custom(val id: Long, val name: String)

需要内部做转换的话:

data class Custom(val id: Long, val name: String) {
    val upName: String
        get() = name.toUpperCase()
}

val ct = Custom(1, "mio4kon")
println(ct.upName)

还可以这样:

val (id, name) = ct

甚至可以这样:

val ct2=ct.copy(name = "mio")

case 4 - 运算符重载

http://kotlinlang.org/docs/reference/operator-overloading.html

具体例子:

gist

util.add(one,two) one.add(two)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
data class Money(val currency: String, val amount: Int)
operator fun Money.plus(other: Money): Money {
if (currency != other.currency) {
throw IllegalArgumentException("currency 不匹配!")
}
return copy(amount = amount + other.amount)
}
fun main(args: Array<String>) {
val one = Money("RMB", 100)
val two = Money("RMB", 200)
val three = one + two
println(three)
}

case 5 - 高阶函数

高阶函数是—参数或者返回值是函数

例子:在onCreate获取View的高度:

java中:

1
2
3
4
5
6
7
8
9
10
mView.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int viewHeight = mView.getHeight();
getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
}
});

Kotlin的话:

mView.waitForLayout{
            //to do
        }
1
2
3
4
5
6
7
8
9
inline fun View.waitForLayout(crossinline f: () -> Unit) = with(viewTreeObserver) {
addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
removeOnGlobalLayoutListener(this)
f()
}
})
}

case 6 - 委托

用java来实现委托给另一个对象来处理的话:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
interface Base {
void println();
}
static class BaseImpl implements Base {
private int x;
public BaseImpl(int x) {
this.x = x;
}
@Override
public void println() {
System.out.println (x);
}
}
//class Derived(b: Base) : Base by b
static class Derived {
private Base base;
public Derived(Base base) {
this.base = base;
}
public void println() {
base.println ();
}
}
public static void main(String[] args) {
BaseImpl base = new BaseImpl (100);
new Derived (base).println ();
}

Kotlin原生就支持它

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface Base {
fun println()
}
class BaseImpl(var x: Int) : Base {
override fun println() {
println(x)
}
}
val b =BaseImpl(100)
class Derived() : Base by b
fun main(args: Array<String>) {
Derived().println()
}

b将会被储存在 Derived 的内部对象中,并且编译器会生成所有的用于转发给b的base的方法

Kotlin有一些标准的委托:Android中比较常用的是lazy:

延迟执行:在第一用到的时候才执行
val toolbar by lazy { find<Toolbar>(R.id.toolbar) }

case 7 - 接口默认方法

场景: 很多类实现了某一接口,接口如果需要增加功能,会影响老的代码.如何为了不影响老代码,同时又可以在新代码上增加新的功能?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
interface Lifecycle {
fun onStart()
fun onDestroy()
//new
fun onStop(){
println("onstop")
}
}
class LifecycleObserver : Lifecycle {
override fun onStart() {
}
override fun onDestroy() {
}
}

case 8 - 强大的集合操作

http://antonioleiva.com/collection-operations-kotlin/

Android 实践

https://github.com/mio4kon/Kotlin-Android-Practice

https://github.com/antoniolg/Bandhook-Kotlin