Kotlin 学习笔记(二)—— 数据类、枚举类、循环、常用集合及操作符的写法(下 )

简介: Kotlin 学习笔记(二)—— 数据类、枚举类、循环、常用集合及操作符的写法(下)

4. Kotlin 常用集合


在 Kotlin 中常用的集合类主要有 List:有序集合,可通过索引访问元素; Set:唯一元素集合,无重复元素的集合;Map:键值对集合,键是唯一的。这 3 种都是 集合接口,这些都和 Java 中的一样。

Kotlin 的集合也可以根据是否可变分为两大类:可变集合 和 不可变集合。不可变集合就是集合中的元素是不可以被修改的,没有 add、remove 等写操作的方法。一般在声明的时候就定义了集合是否可变,可变的集合声明就是 mutableListOf()、mutableSetOf()、mutableMapOf(). 不可变的集合声明是 listOf()、setOf()、mapOf(). 当然,如果在声明的时候就知道集合里的元素,就可以使用这些函数进行初始化:

// code 8
val list = listOf("a", "b", "c", "d")    // 不可变集合声明
val mutableMap = mutableMapOf("name" to "Tom", "age" to "99")    // 可变集合声明

创建空集合的函数用的比较少,分别是 emptyList()、emptySet()、emptyMap() 。而且创建出来的都是只读类型的集合,又不能往里面放元素,所以用的少。

用的较多的当然还是构造函数,以 List 作为说明,Set 和 Map 以此类推。

// code 9
val doubled = List(3, { it * 2 })    // 通过索引 index 初始化集合,初始化了元素个数为 3 的不可变链表。如果需要可变,则用 MutableList
println(doubled)    // 输出:[0, 2, 4]
// 创建具体类型的集合,例如 ArrayList 或 LinkedList,其实这些最后都是调用的 Java 中相应集合类
val linkedList = LinkedList<String>(listOf("one", "two", "three"))    // 创建链表

Kotlin 当然也有数组集合 Array,但是用的并不是很多,基本上以上 3 种集合都可以胜任了。Array 的声明:

// code 10 
val array = Array(5, { it + 1 })    // 初始化长度为 5 的数组 [1,2,3,4,5]
array[0] = 99    // array 可修改元素值,修改后为 [99,2,3,4,5]

与 code 9 中的 List 不一样的是,Array 的这种初始化后的 array 对象,是可以对数组中的元素做修改的,但是其他的 List、Set、Map 都不行。


5. Kotlin 集合操作符


Kotlin 为集合扩展了许多操作符,而且这些操作符还支持链式调用,非常方便。相比于 RxJava 来说,代码量会少很多。照例还是举个栗子吧。下面的例子是将一段字符进行加密转换的操作,先看看 RxJava 是怎么处理的。

// code 11
public class RxJavaExample {
    public static void main(String[] args) {
        final String[] a = new String[]{"4","0","7","i","f","w","0","9"};
        final Integer[] index = new Integer[]{5,3,9,4,8,3,1,9,2,1,7};
        Observable.just(index)    // 1. 传入 index 数组
                .flatMap(new Function<Integer[], ObservableSource<Integer>>() {
                    // flatMap 可将集合拆成一个个元素返回
                    @Override
                    public ObservableSource<Integer> apply(Integer[] integers) throws Throwable {
                        // 2. 调用 flatMap 方法将数组中的 Integer 元素一个个取出
                        return Observable.fromArray(integers);
                    }
                })
                .filter(new Predicate<Integer>() {
                    @Override
                    public boolean test(Integer i) throws Throwable {
                        // 3. 调用 filter 方法,将小于 a 数组长度的 元素 过滤出来
                        // 得到 5,3,4,3,1,2,1,7
                        return i < a.length;
                    }
                })
                .map(new Function<Integer, String>() {
                    // map 可将传入的参数类型,进行转换后输出,这里就是 Integer 转为 String 类型
                    @Override
                    public String apply(Integer integer) throws Throwable {
                        // 4. 调用 map 方法,将得到的一串数字再依次作为 integer 参数输入 a[integer] 中
                        // 得到 "w","i","f","i","0","7","0","9"
                        return a[integer];
                    }
                })
                .reduce(new BiFunction<String, String, String>() {
                    @Override
                    public String apply(String s, String s2) throws Throwable {
                        // 5. 调用 reduce 方法,将 得到的字符串两两组合
                        // 得到 "wifi0709"
                        System.out.println("中间结果:s = " + s + "  s2 = " + s2);
                        return s + s2;
                    }
                })
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Throwable {
                        System.out.println("最终结果:" + s);
                    }
                });
    }
}

RxJava 中有许多的操作符,这里只列举了几个,它们的用法在注释里都可以找到。其中 reduce 的操作我之前是有点不清楚,找到的答案都是说,传入的第一个变量和第二个变量经过处理后,依次两两组合处理,最终得到结果。但到底是怎么个“两两组合处理”?在这里我打印出了中间结果就一目了然了:

image.png

再来看看 Kotlin 的写法:

// code 12
object CollectionOperator {
    private val a = arrayOf("4", "0", "7", "i", "f", "w", "0", "9")
    private val index = arrayOf(5, 3, 9, 4, 8, 3, 1, 9, 2, 1, 7)
    fun exampleOutput() {
        index
            .filter {
                it < a.size
            }
            .map {
                a[it]
            }
            .reduce { s, s2 ->
                "$s$s2"
            }
            .also {
                println("最终结果:s = $it")
            }
    }
}

没想到,Kotlin 的好多集合操作符跟 RxJava 命名都是一样的!而且更好用,比如 Kotlin 不用 flatMap ,自动就将集合中的元素拆成一个个的了,filter 里面的 it 就是代表的集合中的一个个的元素。map、reduce 这不就是借鉴的 RxJava 吗?而且 Kotlin 的 Lambda 表达式使得代码更为简洁。

除了上述的集合操作符,常见的还包括下面的几个操作符,直接在代码中讲解更清楚:

// code 13
val test = listOf("2","3","x","2","g","9","k","o")    // 测试集合
// 1、contains:判断是否含有某元素
println(test.contains("x"))    // 输出:true
println(test.contains("w"))    // 输出:false
// 2、elementAt:返回对应的索引元素,越界会抛出 IndexOutOfBoundsException
println(test.elementAt(3))    // 输出:"2"
// 3、firstOrNull :找出满足条件的第一个元素,若无则返回 null
println(test.firstOrNull { it == "3" })    // 输出:"3"
// 4、indexOf:返回指定元素的索引,若无则返回 -1
println(test.indexOf("k"))    // 输出:6
// 5、singleOrNull:返回满足条件的单个元素,若没有元素满足条件或不止一个元素满足,则返回 null
test.singleOrNull{
    it == "2"
}.also {
    println(it)    // 输出:null
}
// 6、any :集合中任意一个元素若满足条件,则返回 true;否则返回 false
println(test.any { it == "o" })    // 输出:true
val list = listOf(23,-1,4,6,888,34)
// 7、all :集合中所有元素都满足条件,则返回 true;否则返回 false
println(list.all { it < 1000 })    // 输出:true
// 8、none:集合中所有元素都不满足条件,则返回 true;否则返回 false
println(list.none { it - 100 > 100 })    // 输出:false
// 9、count:返回集合中满足条件的元素个数
println(list.count { it > 0 })    // 输出:5
// 10、reduce:集合中第一项和第二项进行处理,得出的结果再和第三项进行处理,一直处理到最后一个元素
println(list.reduce { v1, v2 ->
    v1 + v2
})    // 输出:954
// 11、filter 操作符,过滤,Lambda 表达式是过滤的条件
println(list.filter { it > 0 })    // 输出:[23, 4, 6, 888, 34]
// 12、filterNot 与 filter 是互补的,输出 filter 过滤掉的
println(list.filterNot { it > 0 })    // 输出:[-1]
// 13、filterNotNull:过滤掉 null 的元素
println(listOf(null, 3, 5, null, 8).filterNotNull())
// 14、take:取前 n 个元素
println(list.take(3))    // 输出:[23, -1, 4]
// 15、mapIndexed:带 index 索引信息的 map
println(listOf(35,61,116,74).mapIndexed{ index, i ->
    (i+index).toChar()
})    // 输出:[#, >, v, M]
// 16、mapNotNull:执行map转换前需要过滤掉 null 的元素
println(listOf(null, 33, 55, null, 88).mapNotNull {
    it?.toChar()
})    // 输出:[!, 7, X]
// 17、groupBy:分组操作符。这里就是将 list 分为偶数奇数两组,返回一个 Map
println(list.groupBy { it % 2 == 0 })    // 输出:{false=[23, -1], true=[4, 6, 888, 34]}
// 18、reversed:生成一个与输入集合反序的集合
println(list.reversed())    // 输出:[34, 888, 6, 4, -1, 23]
// 19、sorted:生成一个升序排列集合,原集合不变
println(list.sorted())
// 20、sortedDescending:生成一个降序排列集合,原集合不变
println(list.sortedDescending())
// 21、sortedBy:自定义排序,主要针对 Pair 进行排序
val pairList = listOf(1 to "A", 2 to "B", 5 to "C", 3 to "D")
println(pairList.sortedBy {
    it.first
})    // 输出:[(1, A), (2, B), (3, D), (5, C)]
println(pairList.sortedBy {
    it.second
})    // 输出:[(1, A), (2, B), (5, C), (3, D)]

与 RxJava 类似,Kotlin 也有一个 flatMap 操作符,有许多同学不禁会问了:map 和 flatMap 有啥区别啊?可以根据名称来记,flatMap 有 flat,flat 英文意思是:平的,扁平的;使扁平,它有把集合数据拆开,铺展开的操作。再加个实例说明:

// code 14
val multipList = listOf(listOf(1,9,4,6), listOf("R","U","OK"))
println(multipList.map { it })    // 输出:[[1, 9, 4, 6], [R, U, OK]]
println(multipList.flatMap { it })    // 输出:[1, 9, 4, 6, R, U, OK]

所以还是那句话:纸上得来终觉浅,绝知此事要躬行


更多 Kotlin 笔记可以查看

上一篇:Kotlin 学习笔记(一) www.jianshu.com/p/b3e1b0852…

下一篇:(Writing···)


参考文献


  • 张涛; 极客时间 Kotlin 系列课程
  • Kotlin 官方中文文档。www.kotlincn.net/docs/refere…
  • 全汪汪; Kotlin-Map和flatMap。www.jianshu.com/p/696d307c2…
  • 东海陈光剑; Kotlin 中的集合类排序。blog.csdn.net/universsky2…
目录
相关文章
|
1月前
|
缓存 数据处理 Android开发
Android经典实战之Kotlin常用的 Flow 操作符
本文介绍 Kotlin 中 `Flow` 的多种实用操作符,包括转换、过滤、聚合等,通过简洁易懂的例子展示了每个操作符的功能,如 `map`、`filter` 和 `fold` 等,帮助开发者更好地理解和运用 `Flow` 来处理异步数据流。
74 4
|
1月前
|
缓存 API Android开发
Android经典实战之Kotlin Flow中的3个数据相关的操作符:debounce、buffer和conflate
本文介绍了Kotlin中`Flow`的`debounce`、`buffer`及`conflate`三个操作符。`debounce`过滤快速连续数据,仅保留指定时间内的最后一个;`buffer`引入缓存减轻背压;`conflate`仅保留最新数据。通过示例展示了如何在搜索输入和数据流处理中应用这些操作符以提高程序效率和用户体验。
35 6
|
1月前
|
Kotlin
Kotlin 面向对象编程 (OOP) 基础:类、对象与继承详解
面向对象编程(OOP)是一种编程范式,它通过创建包含数据和方法的对象来组织代码。相较于过程式编程,OOP 提供了更快更清晰的结构,有助于遵守 DRY(Don&#39;t Repeat Yourself)原则,使代码更易于维护和扩展。在 Kotlin 中,类和对象是 OOP 的核心。类作为对象的模板,定义了对象的行为和状态;对象则是类的具体实例。例如,`Car` 类可以定义汽车的品牌、型号等属性,以及如驾驶和刹车等功能。通过构造函数可以快速初始化对象的属性。此外,Kotlin 支持继承机制,子类可以从父类继承属性和方法,促进代码重用。
29 2
|
20天前
|
设计模式 安全 编译器
Kotlin 中的密封类:详解与应用
【8月更文挑战第31天】
44 0
|
20天前
|
设计模式 安全 数据库连接
|
20天前
|
存储 前端开发 编译器
深入理解Kotlin中的数据类及其应用
【8月更文挑战第31天】
10 0
|
1月前
|
Java Android开发 开发者
Kotlin 循环与函数详解:高效编程指南
高效编程实践 • 避免不必要的循环 - 尽量使用集合操作如 map、filter 来减少显式的循环。 • 使用尾递归优化 - 对于需要大量递归的情况,考虑使用尾递归以优化性能。 • 内联函数 - 对于传递 Lambda 表达式的函数,使用 inline 关键字可以减少运行时开销。 通过上述指南,您应该能够更好地理解 Kotlin 中的循环和函数,并能够编写更加高效和简洁的代码。Kotlin 的设计哲学鼓励开发者编写易于理解和维护的代码,而掌握循环和函数是实现这一目标的关键步骤。 如果您想了解更多关于 Kotlin 的循环和函数的信息,以下是一些官方文档和资源,它们可以提供额外的参考
33 1
|
1月前
|
Java Kotlin
Kotlin 循环与函数详解:高效编程指南
Kotlin中的循环结构让你能轻松遍历数组或范围内的元素。使用`for`循环结合`in`操作符,可以简洁地访问数组中的每个项,如字符串数组或整数数组。对于范围,可以用`..`来定义一系列连续的值并进行迭代。此外,Kotlin支持通过`break`和`continue`控制循环流程。函数则允许封装可复用的代码块,你可以定义接受参数并返回值的函数,利用简写语法使代码更加紧凑。例如,`myFunction(x: Int, y: Int) = x + y`简洁地定义了一个计算两数之和的函数。
39 1
|
1月前
|
安全 Java Android开发
Android Kotlin中如何优雅地退出循环?
本文介绍Kotlin中如何在`forEach`循环中提前退出的方法,包括使用`for`循环搭配`break`以及利用标签和`return@标签`的方式。此外,还探讨了标签与`return`、`break`和`continue`在不同场景下的应用,如嵌套循环控制、高阶函数中的提前退出及`inline`函数内的非局部返回等,帮助读者更好地掌握Kotlin的控制流技巧。
39 0
|
3月前
|
存储 API Kotlin
Kotlin中的List集合
Kotlin中的List集合