充分理解Kotlin,快速上手写业务

前言

即便天天10点下班,即便需求不少,我也要用这腐朽的声音喊出:我要学习,我要写文章!!java

几个特性,快速上手Kotlin面试

充分理解Kotlin,快速上手写业务app

快速切换至Kotlin for Android模式ide

聊一聊Kotlin中的协程,真香函数

又是一篇Kotlin的文章,为啥...还不是由于工做须要。毫无疑问,最好的学习方式是经过官方文档去学习。不过我的以为官方文档多多少少有一些不够高效。post

中文官方文档学习

所以这篇是从我学习的我的视角以文档的形式去输出Kotlin语言基础的学习。 不扯淡了,开整。ui

正文

高阶函数

高阶函数是将函数用做参数或返回值的函数。this

我的为何把这个语言特性放在第一位,由于我以为这是咱们Java语言中所不支持的。然而这个特性基本贯穿整个Kotlin语言体系。因此我的把它放到了第一位,也但愿各位小伙伴可以重视这个小小的特性。先看看一个小小的demo,感觉一下这个特别特性:spa

// 函数定义
fun funtion(num: Int, innerFun: (Int) -> Int): Int {
    return innerFun(num)
}
复制代码

简单解释一下上边的代码。咱们先看函数定义,这里定义了一个名为funtion而且返回值为Int的函数,此外这个函数接受一个Int参数和一个函数类型的参数(这个函数须要传递一个Int参数,而且返回一个Int值)。 接下来咱们调用一下:

// 函数调用
val result = funtion(1) {
	it + 666
}
复制代码

对于Lambda来讲,入参若是是一个的话能够用it来表示

说实话,第一次我看到这种调用的时候,是一脸懵逼的。不知道刚入坑的小伙伴是否是和我同样的感觉?由于这种写法包含小tips: 咱们的innerFun是能够被简化为一个Lambda,而当Lambda做为函数的最后一个参数时,是能够将其写在函数以外的。也就是Demo中的funtion(1){}。

此外咱们要注意一点,这里咱们的函数实例,并无return,这是由于。lambda 表达式中的最后一个表达式是返回值 实际上这就是至关于调用了funtion方法的俩个参数,我们换一种传统的写法,两者是等价的:

val inner = fun(num: Int): Int {
	return num + 1
}
val result = funtion(1, inner)
复制代码

OK,接下来我们趁热打铁,再感觉感觉函数操做的“骚操做”。接下来咱们看一看其实状况下的用法:

// 函数定义1
fun funtion(num: Int, innerFun: (Int, Int) -> Int): Int {
    return innerFun(num, num + 1)
}
// 函数调用1(上文提到,入参为1个能够用it表示,那么俩个或者多个呢?咱们能够以下,自定义)
val result = funtion(1) { num1, num2 ->
    num1 + num2 + 666
}
// 函数调用2(除了Lambda的调用方式,咱们还能够用匿名函数,两者是同样的)
val result = funtion(1, fun(num1: Int, num2: Int): Int {
	return num1 + num2 + 666
}
复制代码

OK,关于高阶函数的内容,就聊这么多,由于有了这个其实,不少内容也就很好上手了。接下来就让咱们一同看看基于高阶函数的内置封装。

操做符

集合操做符

我的以为,Kotlin操做符中。开发中颇为经常使用的是集合操做符,好比咱们有时须要对一些数据进行连续的转化,咱们可能会使用RxJava;

Observable.create(new ObservableOnSubscribe<List<CustomModel>>() {
            @Override
            public void subscribe(ObservableEmitter<List<CustomModel>> e) throws Exception {
                // 省略构建List<CustomModel>
                e.onNext(data);
            }
        }).flatMap(new Function<List<CustomModel>, ObservableSource<CustomModel>>() {
            @Override
            public ObservableSource<CustomModel> apply(List<CustomModel> customModels) throws Exception {
                return Observable.fromIterable(customModels);
            }
        }).map(new Function<CustomModel, String>() {
            @Override
            public String apply(CustomModel customModel) throws Exception {
                return customModel.name;
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                // 操做s
            }
        });
复制代码

这里简单,写了一个RxJava的Demo:咱们有一个List集合,先把它一个个发送,而后把每个数据转成String,最后去String进行处理。 而在Kotlin中,应对上述的需求,咱们该怎么作?因为操做符的支持,咱们能够极为方便的进行这类操做:

val data = arrayListOf<CustomModel>(// ...省略构建的过程)
val newData=data.map {
    it.name
}.forEach {
    // 操做it
}
复制代码

用法很简单,乍一看很唬人。可是其实很简单,回忆一下咱们再开篇奠基的高阶函数的基础。这里其实就是调用了data的扩展函数map(拓展函数是一种语法,能够拓展示有的类。好比这个map就是拓展了Iterable,下文咱们会展开它的实现)。对它进行类型转变,而后进而调用forEach自动对这个集合进行遍历。

接下来让咱们点进去,看一看具体的实现:

// 注意看,这里map的**返回值**,是一个List<R>,也就是说最终将返回map后的类型集合。所以咱们能够继续进行链式调用。
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {
    for (item in this)
        destination.add(transform(item))
    return destination
}
复制代码

说白了,这里的集合操做符就是把转化的实现经过参数的形式暴露出来,由咱们自行去处理,其余的事情,有内部封装去作。 固然,这其中还有不少有趣的操做符,各位小伙伴能够自行去了解。不过原理都是大同小异~

做用域函数

上述咱们聊的是做用在集合上的操做符,说白了。它们就是拓展在对应集合类上的函数而已。那么可能有小伙伴会问,有没有做用在对象上的?没错,是有的。也就是咱们接下来要聊的:做用域函数

其实很常见:

"Kotlin".let{
	it.toInt()
}
"Kotlin".run{
	this.toInt()
}

"Kotlin".apply{
}
"Kotlin".also{
}

public inline fun <T, R> T.let(block: (T) -> R): R
public inline fun <T, R> T.run(block: T.() -> R): R

public inline fun <T> T.apply(block: T.() -> kotlin.Unit): T
public inline fun <T> T.also(block: (T) -> kotlin.Unit): T

复制代码

我们看一下,它们哥四个的定义,其实很清晰。这里以返回值的类型,俩俩分类:

  • let/run。这俩个函数均可以返回另外一种类型;不一样在于let有入参,而run没有。
  • also/apply。 这俩个函数返回值都是自己,其中apply没有入参,而also有。

不过即便没有入参,也能够经过this,获得自己。

上述函数的做用仍是挺方便的,好比:

Model model ;
// ...省略初始化过程
if(model!=null){
	// 省略大段的操做逻辑
}
复制代码

这种写法,在kotlin中能够这么写:

model?.alse{
	// 省略大段的操做逻辑
}
// 有需求咱们能够继续调用它的做用域函数
复制代码

若是你还有一些else操做,那么没辙了,kotlin中也只能老老实实if-else

固然,还有一些有趣的做用域函数,好比在Java中:

boolean isTure;
// 省略boolean判断逻辑
if(isTure){
	// 省略大段的操做逻辑
}
复制代码

到Kotlin中能够这样来搞:

某对象.takeIf{
	// boolean判断逻辑
}?.{
	// 省略大段的操做逻辑
}
// 有需求咱们能够继续调用它的做用域函数
复制代码

takeIf:会根据入参的函数的返回值(true/false),决定本身(takeIf)的返回值是null仍是调用者。若是是false,那么就会返回null,所以这里使用?的方式继续去调用后续操做。 我我的比较喜欢做用域函数, 由于能够省略不少if。接下来咱们来换个稍稍复杂的逻辑:已知一个方法,入参是一个Model,咱们要判断当这个Model对象的age属性大于10,打印这个Model对象的名字。 对于Java来讲,咱们可能这么写:

public void fun(Model model) {
	// 写了3个if。
    if (model != null) {
        if (model.age>10){
            if (model.name!=null){
                // 打印model.name
            }
        }
    }
}
    
class Model {
    String name;
    int age;
}
复制代码

对于Kotlin来讲,咱们能够这么写:

fun funtion(model : Model){
	model?.takeIf{
		it.age > 10
	}?.let{
		// 打印it.name
	}
}
复制代码

是否是简洁了不少?可是单说简洁这种东西,彷佛并无什么卵用...不过写起来,真的很爽!不信,你们能够试试~~

尾声

这篇文章,想聊的内容就这么多。我的认为其实理解了高阶函数,(PS:不知道为啥起了个名叫高阶函数,整得好像很高级似的。)Kotlin就能够很快的上手,而且能感觉到Kotlin写起来的爽快之处~ 这里的确有些安利的意味。那是由于本身最开始对新技术其实接受度并不高,总认为新东西有各类各样的问题...当本身去了头条以后,才发现身边的同事那种高昂的学习劲头,(Kotlin?对他们来讲不叫新东西...Jatpack,Flutter都已经在线上项目中跑了)本身还有什么理由说:求求别更新了,我学不动了... 仍是那句话:干就完了!

我是一个应届生,最近和朋友们维护了一个公众号,内容是咱们在从应届生过渡到开发这一路所踩过的坑,以及咱们一步步学习的记录,若是感兴趣的朋友能够关注一下,一同加油~

我的公众号:IT面试填坑小分队
相关文章
相关标签/搜索