Kotlin Power

Android开发者都知道,Google宣布Kotlin First,并且在Android官网上的Demo代码都是Kotlin优先,之后提供的代码也是,推广的决心很大。而且Kotlin和Java能100%兼容,并且语法更简洁,后面我也会陆续写一些Kotlin的分享文章,今天先概览一下Kotlin的优势。

1.类型推断

// 只读变量声明(更友好) 想想final
val a: Int = 1 // 后置类型声明
// 一般利用类型推断,思维更加顺畅,不用再关心参数是什么类型的问题
val a = 5
val s = String()
val clazz = s.getClass()
val method = clazz.getDeclaredMethod("name", null)  
// 可变变量声明
var x = 5

2.View初始化

inline fun <reified TV:View> KView(context: Context, init: TV.() -> Unit) : TV {
    val constructor = TV::class.java.getConstructor(Context::class.java)
    val view : TV = constructor.newInstance(context)
    view.init()
    return view
}

>>> usage
val view = KView<TextView>(this) {
        layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT)
        text = "Hello"
}

3.NUllPointer

空类型和非空类型

var age: String? = null
// 直接调用会编译报错
val age1 = age.toInt()
// 正确调用
val age1 = age?.toInt()

// 不做处理返回null
val age2 = age?.toInt()
// age为空返回-1
val age2 = age?.toInt() ?: -1
// 抛出空指针异常
val age2 = age!!.toInt()

val l = s?.length // s != null, l = s.length else l = null, l: Int?
val l = s!!.length // same as l = s.length in java, l: Int
val l = s?.length ?: 0 //  s != null, l = s.length else l = 0, l: Int
return myValue ?: -1
// 链式使用:
bob?.department?.head?.name // 任一为null不执行

Attention:

如果被Java调用,由于Java无法保证非空(除非已经使用@NonNull注解注明),从Java接收的参数必须是可空的。

4. ? and Elvis

// java
if(view != null) {
  if(view.getParent() != null) {
    if(view.getParent() instanceof ViewGroup) {
      ((ViewGroup) view.getParent()).removeView(view)
    }
  }
}

// kotlin
(view?.parent as? ViewGroup)?.removeView(view)

5. when

when(x) {
  in 1..10 -> print("x is in the range")
  !in 10..20 -> print("x is outside the range")
  is String -> print("x is a string")
  else -> print("none of the above")
}

// usage
if(TextUtils.equals(day, today)) {
  xxx1
} else if(TextUtils.equals(day, tomorrow)) {
  xxx2
} else {
  xxx3
}

// kotlin
when(day) {
  today -> xxx1
  tomorrow -> xxx2
  else -> xxx3
}

6. 扩展函数

private fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
    val tmp: T = this[index1]
    this[index1] = this[index2]
    this[index2] = tmp
}

>>> usage
val list = mutableListOf<Int>(1, 2, 3)
list.swap(0, 1)
println(list)

>>> out
[2, 1, 3]

7. 关键字object

单例

object KotlinPower {
    override fun toString(): String {
        return "KotlinPower"
    }
}

>>> usage
println(KotlinPower.toString())

对象字面量

fun testObject() {
    val a = object {
        var x: Int = 0
        var y: Int = 0
    }

    println("a.x: ${a.x}, a.y: ${a.y}")
}

>>> usage
    testObject()

>>> out
a.x: 0, a.y: 0

再看一个例子:

object Test {
    fun sayMessage(msg: String) {
        println("from Kotlin $msg")
    }
}
// kotlin code
Test.sayMessage("Hello")

// java code
Test.INSTANCE.sayMessage("hello");

如果要保持java和Kotlin中的调用方式一样,可以在Kotlin中通过注解@JvmStatic方式

object Test {
    @JvmStatic
    fun sayMessage(msg: String) {
        println("from Kotlin $msg")
    }
}
//这样在java中就可以直接
Test.sayMessage("Hello")

8. 属性

引入了属性的概念,隐式的gettersetter

var stringRepresentation: String
    get() = this.toString()
    set(value) {
        setDataFromString(value)
    }

// 相当于
    
public String getStringRepresentation() {
    return this.toString();
}

public void setStringRepresentation(String value) {
    setDataFromString(value)  
}

9.函数

在Kotlin中函数成为了一等公民,位置不需要一定在类的内部,可以和类成为顶级函数,函数也可以作为参数传递

  • 缺省参数,命名参数

可以简化重载,不用再使用Builder等优势

fun reformat(str: String,
             normalizeCase: Boolean = true,
             upperCaseFirstLetter: Boolean = true,
             divideByCamelHumps: Boolean = false,
             wordSeparator: Char = ' ') {
    // do something
}
reformat(str)
reformat(str, wordSeparator = ' ') // 可以使用参数的名字给缺省参数赋值
// 可以通过@JvmOverloads注解生成Java的重载形式便于Java来调用
  • 扩展函数

可以去掉Java中到处存在的XXXUtils.java类

// Java
// 写一个Util类,作为参数传进去
public class ViewUtils {
    public static int findColor(View view, int resId) {
        return view.getResources().getColor(resId);
    }
}
ViewUtils.findColor(view, resId);

使用Kotlin简化如下:

fun View.findColor(id: Int) : Int {
    return this.resources.getColor(id)
}

view.findColor(resId)

一系列这种类型的Java工具类在Kotlin中被“改造”成了扩展方法例如:

Collection.sort(list)在Kotlin中直接list.sort()就可以了。

可以完全取代以往的Util类。

10.作用域函数

  • let/run

对象作为参数传入lambdarun则作为this),返回值为lambda表达式的返回值, 常见场景:转换类型,处理nullable类型

// if...else...写法
private fun testIfElse(): Object? {
    return if (a !== null) {
        val b = handleA(a)
        if (b !== null) {
            handleB(b)
        } else {
            null
        }
    } else {
        null
    }
}
 
// ?.let写法
private fun testLet(): Object? {
    return a?.let { handleA(it) }?.let { handleB(it) }
}
  • apply

对象作为this传入lambda, 返回值为对象本身,常见场景:初始化对象

  • also

对象作为参数传入lambda,返回值为对象本身,常见场景:链式调用中的副作用

// transforming data from api with intermediary variable
val rawData = api.getData()
Log.debug(rawData)
rawData.map {  /** other stuff */  }
// use 'also' to stay in the method chains
api.getData()
    .also { Log.debug(it) }
    .map { /** other stuff */ }
  • takeIf/takeUnless

对象作为参数传入lambda,返回值为对象本身或null(根据lambda中语句的true or false),常见场景:链式调用形式的条件判断

File(url).takeIf { it.exists() }
        ?.let {
            JSONObject(NetworkUtils.postFile(20 * 1024, "http://i.snssdk.com/2/data/upload_image/", "image", url))
        }?.takeIf { it.optString("message") == "success" }
        ?.let {
            post(content, contact, it.optJSONObject("data")?.optString("web_uri"))
        } ?: mHandler.post { view?.onFail() }

11.Lambda

本质上是一个匿名方法(单方法接口)

fun isGreaterThanZero(n: Int): Boolean {
    return n > 0
}

collection.filter(::isGreaterThanZero)
// 使用Lambda
collection.filter{ i: Int -> i > 0 }
collection.filter{ i -> i > 0 }
collection.filter{ it > 0 }

单方法接口都可以传Lambda

button.setOnClickListener(new View.OnClickListener() {
    
    public void onClick(View v) {
        showToast();
    }
});

button.setOnClickListener{ showToast() }

内置常用的流处理Lambda

names
.filter{ it.startsWith("A") }
.sortedBy{ it }
.map{ it.toUpperCase() }
.forEach{ print(it) }

12.其他

  • 支持运算符重载
  • 接口可以有缺省方法
  • Data Class数据类型,自动实现`equals/hashCode/toString
  • 协程
  • 伴生对象

Refs:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345