4

Kotlin Primer·第六章·集合泛型与操作符

 2 years ago
source link: https://www.kymjs.com/code/2017/06/06/01/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Kotlin Primer·第六章·集合泛型与操作符

2017-06-06 By 张涛 | 本文已被访问 12019 次

版权声明:本文是开源实验室原创文章,如您转载必须以链接形式注明原文地址:https://kymjs.com/code/2017/06/06/01
妈的,推了两年的 Kotlin 不如 Google 的一句话。庆祝 Kotlin 小三转正了。
如果你觉得我的 Kotlin 博客对你有帮助,那么我强烈建议你看看我的极客时间 Kotlin 视频课程。视频中讲述了很多实际开发中遇到问题的解决办法,以及很多 Kotlin 特性功能在工作中实际项目上的应用场景。
对本文有任何问题,可加我的个人微信询问:kymjs123

题外话:全书的目录以及主要内容已经公开,可在我公众号【技术实验室】的历史推送文章查看

第一部分——快速上手
第一章·启程
第二章·基本语法
第三章·Kotlin 与 Java 混编
第二部分——开始学习 Kotlin
第四章·Kotlin 的类特性(上)
第四章·Kotlin 的类特性(下)
第五章·函数与闭包
第六章·集合泛型与操作符
第三部分——Kotlin 工具库
第七章·协程库(上篇)
第七章·协程库(中篇)

所谓泛型:就是允许在定义类、接口、方法时指定类型形参,这个类型形参将在声明变量、创建对象、调用方法时动态地指定(即传入实际的类型参数,也可称为类型实参)。 Kotlin 泛型定义与 Java 类似,但有着更多特性支持。首先,我们来看看集合类中的泛型声明。

6.1 Kotlin 中的集合接口

kotlin 集合类

以上是 Kotlin 的集合接口关系,从上到下,依次下面继承(或实现)上面的接口。

所有类声明的泛型尖括号里面如果加入了 out 关键字,则说明这个类的对象是只读的,例如他只有:get()、size()等方法,而没有 set()、remove()等方法。
相反的,如果没有加 out 关键字,或者换一种记法:如果开头是 MutableXXX 那就是一个跟 Java 中用法一致的集合类。

6.2 in 与 out

至此,你应该已经知道 out 关键字的含义了,与 out 对应的,还有一个 in。表示泛型参数是只写的。
泛型的 in 关键字一般用在我们定义的代码中。 在看下面这个 demo 之前,你需要知道一点:Kotlin 的泛型是支持协变的。例如下面这段代码:

open class A
open class B : A()
open class C : B()

val mutableList: MutableList<B> = mutableListOf(B(), B(), C())
val list: List<A> = mutableList;

在 Kotlin 中,可以直接把 List<C> 的对象赋值给 List<A>
知道了上面这一点,我们接下来看 in 的用法。
泛型声明中,用 in 声明泛型参数,表示这个参数只能是入参,不能对外返回这个参数。

open class A
open class B : A()
open class C : B()

class TypeArray<in A> {

    //in 修饰了 A,表示 A 是可以作为参数的。
    fun getValue(a: A): Int? {
        return a?.hashCode()
    }

    //这段代码是非法的,因为A 不能被返回
    fun getA(a: A): A? {
        return a
    }
}

6.3 集合的初始化

在 Kotlin 中,集合类一般不使用构造方法去初始化,而是使用同一的入口方法,例如初始化一个 MutableList,我们使用的是如下代码:

 val mutableList = mutableListOf(0, 1, 2, 3) 

类似的初始化集合对象的方法还有

//创建一个 List<> 对象
var list = listOf(0, 1, 2)

//创建一个 Set<> 对象
val ss = setOf(1, 2, 4)

还有很多,可以在 kotlin.collections.Collections.kt文件中查看。
有一点需要知道的是,这些方法的返回值实际上返回的是 Java 的集合对象,目前只支持返回这些对象:

java.util.ArrayList
java.util.LinkedHashMap
java.util.HashMap
java.util.LinkedHashSet
java.util.HashSet
java.util.SortedSet
java.util.TreeSet

其他的对象,目前还不支持,比如 LinkedList,个人觉得这个对象还是很常用的,不知道为什么没有方法提供,所以目前这类对象还是只能用构造方法去创建。

6.4 操作符

Kotlin 中,操作符是用来对数据做操作的工具方法。
如果你使用过 RxJava 等一系列库,你一定会对操作符非常了解也对操作符的强大深有感触。
Kotlin 原生支持大量操作符,文尾将会列出常用操作符及含义。 这两幅图是我上周在《从 Java 到 Kotlin,当机器人不再喝咖啡》 技术分享时 PPT 中的两页,代码运行后是当时会场的 WiFi 密码,大家可以感受一下用 Kotlin 和 Java 实现的对比。

kotlin 集合类

kotlin 集合类

6.5 操作符实现原理

以最简单也是最常用的一个操作符 forEach 举例。

list.forEach {          
}

在 Kotlin 中,操作符本质上是方法调用。例如 List 的 forEach 的实现原理实际上是定义了一个这样的方法。为 Iterable 增加了一个扩展方法,叫 forEach,它接收一个 T 作为参数,并返回 Unit 的闭包作为参数。

public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
    for (element in this) action(element)
}

而内部,实际上就是 for 循环对每一个对象调用传入的参数方法。

所以,我们也可以很轻松的通过这样的特性实现自己的自定义操作符。例如下面的代码为一个 List 添加一个转换操作符,可以将 List<A> 转换成 List<B>,其中 A 和 B 可以为任何类型。

inline fun <T, E> Iterable<T>.convert(action: (T) -> E): MutableList<E> {
    val list: MutableList<E> = mutableListOf()
    for (element in this) list.add(action(element))
    return list
}

{
    val list: List<String> = listOf("hello","world")
    list.convert {
            it.hashCode()
        }.forEach {
            print("$it")
        }
}()

这样子就可以直接调用 list 的 convert 方法,只需要实现转换逻辑,就可以了。

6.6 常用操作符

Kotlin 的操作符跟 RxJava 基本一致,不需要额外记忆。

下标操作类
  • contains —— 判断是否有指定元素
  • elementAt —— 返回对应的元素,越界会抛IndexOutOfBoundsException
  • firstOrNull —— 返回符合条件的第一个元素,没有 返回null
  • lastOrNull —— 返回符合条件的最后一个元素,没有 返回null
  • indexOf —— 返回指定元素的下标,没有 返回-1
  • singleOrNull —— 返回符合条件的单个元素,如有没有符合或超过一个,返回null
  • any —— 判断集合中 是否有满足条件 的元素
  • all —— 判断集合中的元素 是否都满足条件
  • none —— 判断集合中是否 都不满足条件,是则返回true
  • count —— 查询集合中 满足条件 的 元素个数
  • reduce —— 从 第一项到最后一项进行累计
  • filter —— 过滤 掉所有 满足条件 的元素
  • filterNot —— 过滤所有不满足条件的元素
  • filterNotNull —— 过滤NULL
  • take —— 返回前 n 个元素
  • map —— 转换成另一个集合(与上面我们实现的 convert 方法作用一样);
  • mapIndexed —— 除了转换成另一个集合,还可以拿到Index(下标);
  • mapNotNull —— 执行转换前过滤掉 为 NULL 的元素
  • flatMap —— 自定义逻辑合并两个集合;
  • groupBy —— 按照某个条件分组,返回Map;
  • reversed —— 反序
  • sorted —— 升序
  • sortedBy —— 自定义排序
  • sortedDescending —— 降序
了解更多有深度技术的文章,与移动端、大前端未来方向的认知,前往订阅 开源实验室小专栏。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK